summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java8
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java45
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java3
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java87
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java4
-rw-r--r--cmds/idmap2/Android.bp9
-rw-r--r--cmds/statsd/src/StatsService.cpp5
-rw-r--r--cmds/statsd/src/atoms.proto164
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp5
-rw-r--r--cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp4
-rw-r--r--core/java/android/app/AppOpsManager.java3
-rw-r--r--core/java/android/content/pm/PackageParser.java38
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java26
-rw-r--r--core/java/android/os/incremental/IIncrementalService.aidl5
-rw-r--r--core/java/android/os/incremental/IncrementalFileStorages.java7
-rw-r--r--core/java/android/os/incremental/IncrementalStorage.java11
-rw-r--r--core/java/android/view/InsetsState.java29
-rw-r--r--core/java/com/android/internal/app/ResolverListAdapter.java2
-rw-r--r--core/java/com/android/server/SystemConfig.java4
-rw-r--r--core/proto/android/server/blobstoremanagerservice.proto70
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/res/res/values/strings.xml3
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--media/java/android/media/MediaRouter2Manager.java4
-rw-r--r--packages/PackageInstaller/res/values-ne/strings.xml8
-rw-r--r--packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java14
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-el/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-hy/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-sq/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-uk/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-vi/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-it/arrays.xml20
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java21
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java17
-rw-r--r--packages/Shell/res/values-it/strings.xml2
-rw-r--r--packages/Shell/res/values-ky/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-it/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml8
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-da/strings.xml4
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml14
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml3
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-in/strings.xml2
-rw-r--r--packages/SystemUI/res/values-it/strings.xml8
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml3
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml3
-rw-r--r--packages/SystemUI/res/values-my/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml5
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-or/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml3
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml5
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-th/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml5
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml12
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java224
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/UserAwareController.kt (renamed from packages/SystemUI/src/com/android/systemui/util/UserAwareController.kt)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java64
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java128
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt364
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java45
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt209
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java49
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java82
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java157
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java56
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java13
-rw-r--r--services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java6
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java14
-rw-r--r--services/core/java/com/android/server/notification/CalendarTracker.java16
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java8
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java6
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java52
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java38
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java2
-rw-r--r--services/core/java/com/android/server/wm/BarController.java11
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java14
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java104
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java24
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/StatusBarController.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java26
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java81
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java40
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java42
-rw-r--r--services/incremental/BinderIncrementalService.cpp5
-rw-r--r--services/incremental/BinderIncrementalService.h2
-rw-r--r--services/incremental/IncrementalService.cpp49
-rw-r--r--services/incremental/IncrementalService.h9
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp28
-rw-r--r--services/tests/servicestests/AndroidManifest.xml1
-rw-r--r--services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java41
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java33
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java27
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java86
-rw-r--r--telephony/java/android/telephony/PhysicalChannelConfig.java8
-rw-r--r--telephony/java/android/telephony/ServiceState.java20
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java134
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl29
176 files changed, 2800 insertions, 1301 deletions
diff --git a/Android.bp b/Android.bp
index 632f49da5df9..7c2d6eb9301e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -264,6 +264,7 @@ filegroup {
":libcamera_client_aidl",
":libcamera_client_framework_aidl",
":libupdate_engine_aidl",
+ ":resourcemanager_aidl",
":storaged_aidl",
":vold_aidl",
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
index 96bb5ef4e45e..ba0fab6b4bc5 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
@@ -127,6 +127,14 @@ class BlobAccessMode {
return false;
}
+ int getAccessType() {
+ return mAccessType;
+ }
+
+ int getNumWhitelistedPackages() {
+ return mWhitelistedPackages.size();
+ }
+
void dump(IndentingPrintWriter fout) {
fout.println("accessType: " + DebugUtils.flagsToString(
BlobAccessMode.class, "ACCESS_TYPE_", mAccessType));
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index 03573d966cd0..7e8c90632fd9 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -54,6 +54,8 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.StatsEvent;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -414,6 +416,49 @@ class BlobMetadata {
return true;
}
+ StatsEvent dumpAsStatsEvent(int atomTag) {
+ synchronized (mMetadataLock) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ // Write Committer data to proto format
+ for (int i = 0, size = mCommitters.size(); i < size; ++i) {
+ final Committer committer = mCommitters.valueAt(i);
+ final long token = proto.start(
+ BlobStatsEventProto.BlobCommitterListProto.COMMITTER);
+ proto.write(BlobStatsEventProto.BlobCommitterProto.UID, committer.uid);
+ proto.write(BlobStatsEventProto.BlobCommitterProto.COMMIT_TIMESTAMP_MILLIS,
+ committer.commitTimeMs);
+ proto.write(BlobStatsEventProto.BlobCommitterProto.ACCESS_MODE,
+ committer.blobAccessMode.getAccessType());
+ proto.write(BlobStatsEventProto.BlobCommitterProto.NUM_WHITELISTED_PACKAGE,
+ committer.blobAccessMode.getNumWhitelistedPackages());
+ proto.end(token);
+ }
+ final byte[] committersBytes = proto.getBytes();
+
+ proto = new ProtoOutputStream();
+ // Write Leasee data to proto format
+ for (int i = 0, size = mLeasees.size(); i < size; ++i) {
+ final Leasee leasee = mLeasees.valueAt(i);
+ final long token = proto.start(BlobStatsEventProto.BlobLeaseeListProto.LEASEE);
+ proto.write(BlobStatsEventProto.BlobLeaseeProto.UID, leasee.uid);
+ proto.write(BlobStatsEventProto.BlobLeaseeProto.LEASE_EXPIRY_TIMESTAMP_MILLIS,
+ leasee.expiryTimeMillis);
+ proto.end(token);
+ }
+ final byte[] leaseesBytes = proto.getBytes();
+
+ // Construct the StatsEvent to represent this Blob
+ return StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeLong(mBlobId)
+ .writeLong(getSize())
+ .writeLong(mBlobHandle.getExpiryTimeMillis())
+ .writeByteArray(committersBytes)
+ .writeByteArray(leaseesBytes)
+ .build();
+ }
+ }
+
void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) {
fout.println("blobHandle:");
fout.increaseIndent();
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
index 656726622cfd..08ee24460722 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
@@ -49,6 +49,9 @@ class BlobStoreConfig {
public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_SESSION_CREATION_TIME;
+ public static final long INVALID_BLOB_ID = 0;
+ public static final long INVALID_BLOB_SIZE = 0;
+
private static final String ROOT_DIR_NAME = "blobstore";
private static final String BLOBS_DIR_NAME = "blobs";
private static final String SESSIONS_INDEX_FILE_NAME = "sessions_index.xml";
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 68c4bb675907..850a1d25339c 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -28,6 +28,8 @@ import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.os.UserHandle.USER_CURRENT;
import static android.os.UserHandle.USER_NULL;
+import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_ID;
+import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_SIZE;
import static com.android.server.blob.BlobStoreConfig.LOGV;
import static com.android.server.blob.BlobStoreConfig.TAG;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT;
@@ -48,6 +50,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.StatsManager;
import android.app.blob.BlobHandle;
import android.app.blob.BlobInfo;
import android.app.blob.IBlobStoreManager;
@@ -80,6 +83,7 @@ import android.util.ExceptionUtils;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.StatsEvent;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -88,6 +92,7 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
@@ -159,6 +164,8 @@ public class BlobStoreManagerService extends SystemService {
new SessionStateChangeListener();
private PackageManagerInternal mPackageManagerInternal;
+ private StatsManager mStatsManager;
+ private StatsPullAtomCallbackImpl mStatsCallbackImpl = new StatsPullAtomCallbackImpl();
private final Runnable mSaveBlobsInfoRunnable = this::writeBlobsInfo;
private final Runnable mSaveSessionsRunnable = this::writeBlobSessions;
@@ -192,6 +199,7 @@ public class BlobStoreManagerService extends SystemService {
LocalServices.addService(BlobStoreManagerInternal.class, new LocalService());
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+ mStatsManager = getContext().getSystemService(StatsManager.class);
registerReceivers();
LocalServices.getService(StorageStatsManagerInternal.class)
.registerStorageStatsAugmenter(new BlobStorageStatsAugmenter(), TAG);
@@ -207,6 +215,7 @@ public class BlobStoreManagerService extends SystemService {
readBlobSessionsLocked(allPackages);
readBlobsInfoLocked(allPackages);
}
+ registerBlobStorePuller();
} else if (phase == PHASE_BOOT_COMPLETED) {
BlobStoreIdleJobService.schedule(mContext);
}
@@ -219,7 +228,7 @@ public class BlobStoreManagerService extends SystemService {
long sessionId;
do {
sessionId = Math.abs(mRandom.nextLong());
- if (mKnownBlobIds.indexOf(sessionId) < 0 && sessionId != 0) {
+ if (mKnownBlobIds.indexOf(sessionId) < 0 && sessionId != INVALID_BLOB_ID) {
return sessionId;
}
} while (n++ < 32);
@@ -376,9 +385,23 @@ public class BlobStoreManagerService extends SystemService {
.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
callingPackage, callingUid)) {
+ if (blobMetadata == null) {
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid,
+ INVALID_BLOB_ID, INVALID_BLOB_SIZE,
+ FrameworkStatsLog.BLOB_OPENED__RESULT__BLOB_DNE);
+ } else {
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid,
+ blobMetadata.getBlobId(), blobMetadata.getSize(),
+ FrameworkStatsLog.BLOB_LEASED__RESULT__ACCESS_NOT_ALLOWED);
+ }
throw new SecurityException("Caller not allowed to access " + blobHandle
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
}
+
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid,
+ blobMetadata.getBlobId(), blobMetadata.getSize(),
+ FrameworkStatsLog.BLOB_OPENED__RESULT__SUCCESS);
+
return blobMetadata.openForRead(callingPackage);
}
}
@@ -391,19 +414,41 @@ public class BlobStoreManagerService extends SystemService {
.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
callingPackage, callingUid)) {
+ if (blobMetadata == null) {
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+ INVALID_BLOB_ID, INVALID_BLOB_SIZE,
+ FrameworkStatsLog.BLOB_LEASED__RESULT__BLOB_DNE);
+ } else {
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+ blobMetadata.getBlobId(), blobMetadata.getSize(),
+ FrameworkStatsLog.BLOB_LEASED__RESULT__ACCESS_NOT_ALLOWED);
+ }
throw new SecurityException("Caller not allowed to access " + blobHandle
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
}
if (leaseExpiryTimeMillis != 0 && blobHandle.expiryTimeMillis != 0
&& leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) {
+
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+ blobMetadata.getBlobId(), blobMetadata.getSize(),
+ FrameworkStatsLog.BLOB_LEASED__RESULT__LEASE_EXPIRY_INVALID);
throw new IllegalArgumentException(
"Lease expiry cannot be later than blobs expiry time");
}
if (blobMetadata.getSize()
> getRemainingLeaseQuotaBytesInternal(callingUid, callingPackage)) {
+
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+ blobMetadata.getBlobId(), blobMetadata.getSize(),
+ FrameworkStatsLog.BLOB_LEASED__RESULT__DATA_SIZE_LIMIT_EXCEEDED);
throw new LimitExceededException("Total amount of data with an active lease"
+ " is exceeding the max limit");
}
+
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+ blobMetadata.getBlobId(), blobMetadata.getSize(),
+ FrameworkStatsLog.BLOB_LEASED__RESULT__SUCCESS);
+
blobMetadata.addOrReplaceLeasee(callingPackage, callingUid,
descriptionResId, description, leaseExpiryTimeMillis);
if (LOGV) {
@@ -587,6 +632,9 @@ public class BlobStoreManagerService extends SystemService {
blob.addOrReplaceCommitter(newCommitter);
try {
writeBlobsInfoLocked();
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED,
+ session.getOwnerUid(), blob.getBlobId(), blob.getSize(),
+ FrameworkStatsLog.BLOB_COMMITTED__RESULT__SUCCESS);
session.sendCommitCallbackResult(COMMIT_RESULT_SUCCESS);
} catch (Exception e) {
if (existingCommitter == null) {
@@ -595,6 +643,9 @@ public class BlobStoreManagerService extends SystemService {
blob.addOrReplaceCommitter(existingCommitter);
}
Slog.d(TAG, "Error committing the blob", e);
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED,
+ session.getOwnerUid(), blob.getBlobId(), blob.getSize(),
+ FrameworkStatsLog.BLOB_COMMITTED__RESULT__ERROR_DURING_COMMIT);
session.sendCommitCallbackResult(COMMIT_RESULT_ERROR);
}
getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
@@ -1684,6 +1735,40 @@ public class BlobStoreManagerService extends SystemService {
}
}
+ private void registerBlobStorePuller() {
+ mStatsManager.setPullAtomCallback(
+ FrameworkStatsLog.BLOB_INFO,
+ null, // use default PullAtomMetadata values
+ BackgroundThread.getExecutor(),
+ mStatsCallbackImpl
+ );
+ }
+
+ private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback {
+ @Override
+ public int onPullAtom(int atomTag, List<StatsEvent> data) {
+ switch (atomTag) {
+ case FrameworkStatsLog.BLOB_INFO:
+ return pullBlobData(atomTag, data);
+ default:
+ throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
+ }
+ }
+ }
+
+ private int pullBlobData(int atomTag, List<StatsEvent> data) {
+ synchronized (mBlobsLock) {
+ for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
+ final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
+ for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
+ final BlobMetadata blob = userBlobs.valueAt(j);
+ data.add(blob.dumpAsStatsEvent(atomTag));
+ }
+ }
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
private class LocalService extends BlobStoreManagerInternal {
@Override
public void onIdleMaintenance() {
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index a10b0b324f83..51cf805aa000 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -53,6 +53,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
@@ -450,6 +451,9 @@ class BlobStoreSession extends IBlobStoreSession.Stub {
+ ") didn't match the given BlobHandle.digest ("
+ BlobHandle.safeDigest(mBlobHandle.digest) + ")");
mState = STATE_VERIFIED_INVALID;
+
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED, getOwnerUid(), mSessionId,
+ getSize(), FrameworkStatsLog.BLOB_COMMITTED__RESULT__DIGEST_MISMATCH);
sendCommitCallbackResult(COMMIT_RESULT_ERROR);
}
mListener.onStateChanged(this);
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index fb5830506925..878cef94b674 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -23,9 +23,16 @@ cc_defaults {
"misc-*",
"readability-*",
],
+ tidy_checks_as_errors: [
+ "modernize-*",
+ "-modernize-avoid-c-arrays",
+ "-modernize-use-trailing-return-type",
+ "android-*",
+ "misc-*",
+ "readability-*",
+ ],
tidy_flags: [
"-system-headers",
- "-warnings-as-errors=*",
],
}
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 47bab2947aaf..6f952f637506 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -267,8 +267,11 @@ void StatsService::dumpIncidentSection(int out) {
for (const ConfigKey& configKey : mConfigManager->GetAllConfigKeys()) {
uint64_t reportsListToken =
proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST);
+ // Don't include the current bucket to avoid skipping buckets.
+ // If we need to include the current bucket later, consider changing to NO_TIME_CONSTRAINTS
+ // or other alternatives to avoid skipping buckets for pulled metrics.
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
- true /* includeCurrentBucket */, false /* erase_data */,
+ false /* includeCurrentBucket */, false /* erase_data */,
ADB_DUMP,
FAST,
&proto);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e998711ef3c0..278278fc18c4 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -478,13 +478,16 @@ message Atom {
296;
MediametricsAudioDeviceConnectionReported mediametrics_audiodeviceconnection_reported =
297;
+ BlobCommitted blob_committed = 298 [(module) = "framework"];
+ BlobLeased blob_leased = 299 [(module) = "framework"];
+ BlobOpened blob_opened = 300 [(module) = "framework"];
// StatsdStats tracks platform atoms with ids upto 500.
// Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
}
// Pulled events will start at field 10000.
- // Next: 10081
+ // Next: 10084
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
@@ -575,7 +578,7 @@ message Atom {
SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
SettingSnapshot setting_snapshot = 10080 [(module) = "framework"];
- //10081 free for use
+ BlobInfo blob_info = 10081 [(module) = "framework"];
DataUsageBytesTransfer data_usage_bytes_transfer = 10082 [(module) = "framework"];
BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered =
10083 [(module) = "framework"];
@@ -4905,6 +4908,94 @@ message SnapshotMergeReported {
optional int64 cow_file_size_bytes = 5;
}
+/**
+ * Event representing when BlobStoreManager.Session#commit() is called
+ *
+ * Logged from:
+ * frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+ */
+message BlobCommitted {
+ // Uid of the Blob committer
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Id of the Blob committed
+ optional int64 blob_id = 2;
+
+ // Size of the Blob
+ optional int64 size = 3;
+
+ enum Result {
+ UNKNOWN = 0;
+ // Commit Succeeded
+ SUCCESS = 1;
+ // Commit Failed: Error occurred during commit
+ ERROR_DURING_COMMIT = 2;
+ // Commit Failed: Digest of the data did not match Blob digest
+ DIGEST_MISMATCH = 3;
+ }
+ optional Result result = 4;
+}
+
+/**
+ * Event representing when BlobStoreManager#acquireLease() is called
+ *
+ * Logged from:
+ * frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+ */
+message BlobLeased{
+ // Uid of the Blob leasee
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Id of the Blob leased or 0 if the Blob does not exist
+ optional int64 blob_id = 2;
+
+ // Size of the Blob or 0 if the Blob does not exist
+ optional int64 size = 3;
+
+ enum Result {
+ UNKNOWN = 0;
+ // Lease Succeeded
+ SUCCESS = 1;
+ // Lease Failed: Blob does not exist
+ BLOB_DNE = 2;
+ // Lease Failed: Leasee does not have access to the Blob
+ ACCESS_NOT_ALLOWED = 3;
+ // Lease Failed: Leasee requested an invalid expiry duration
+ LEASE_EXPIRY_INVALID = 4;
+ // Lease Failed: Leasee has exceeded the total data lease limit
+ DATA_SIZE_LIMIT_EXCEEDED = 5;
+ }
+ optional Result result = 4;
+}
+
+/**
+ * Event representing when BlobStoreManager#openBlob() is called
+ *
+ * Logged from:
+ * frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+ */
+message BlobOpened{
+ // Uid of the Blob opener
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Id of the Blob opened or 0 if the Blob does not exist
+ optional int64 blob_id = 2;
+
+ // Size of the Blob or 0 if the Blob does not exist
+ optional int64 size = 3;
+
+ enum Result {
+ UNKNOWN = 0;
+ // Open Succeeded
+ SUCCESS = 1;
+ // Open Failed: Blob does not exist
+ BLOB_DNE = 2;
+ // Open Failed: Opener does not have access to the Blob
+ ACCESS_NOT_ALLOWED = 3;
+ }
+ optional Result result = 4;
+}
+
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
@@ -10791,3 +10882,72 @@ message MediametricsAudioDeviceConnectionReported {
// Number of connections if aggregated statistics, otherwise 1.
optional int32 connection_count = 6;
}
+
+// Blob Committer stats
+// Keep in sync between:
+// frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+// frameworks/base/cmds/statsd/src/atoms.proto
+message BlobCommitterProto {
+ // Committer app's uid
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Unix epoch timestamp of the commit in milliseconds
+ optional int64 commit_timestamp_millis = 2;
+
+ // Flags of what access types the committer has set for the Blob
+ optional int32 access_mode = 3;
+
+ // Number of packages that have been whitelisted for ACCESS_TYPE_WHITELIST
+ optional int32 num_whitelisted_package = 4;
+}
+
+// Blob Leasee stats
+// Keep in sync between:
+// frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+// frameworks/base/cmds/statsd/src/atoms.proto
+message BlobLeaseeProto {
+ // Leasee app's uid
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Unix epoch timestamp for lease expiration in milliseconds
+ optional int64 lease_expiry_timestamp_millis = 2;
+}
+
+// List of Blob Committers
+// Keep in sync between:
+// frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+// frameworks/base/cmds/statsd/src/atoms.proto
+message BlobCommitterListProto {
+ repeated BlobCommitterProto committer = 1;
+}
+
+// List of Blob Leasees
+// Keep in sync between:
+// frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+// frameworks/base/cmds/statsd/src/atoms.proto
+message BlobLeaseeListProto {
+ repeated BlobLeaseeProto leasee = 1;
+}
+
+/**
+ * Logs the current state of a Blob committed with BlobStoreManager
+ *
+ * Pulled from:
+ * frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+ */
+message BlobInfo {
+ // Id of the Blob
+ optional int64 blob_id = 1;
+
+ // Size of the Blob data
+ optional int64 size = 2;
+
+ // Unix epoch timestamp of the Blob's expiration in milliseconds
+ optional int64 expiry_timestamp_millis = 3;
+
+ // List of committers of this Blob
+ optional BlobCommitterListProto committers = 4;
+
+ // List of leasees of this Blob
+ optional BlobLeaseeListProto leasees = 5;
+}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 0a0bdb3baa1b..5987a723a421 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -960,7 +960,10 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
int64_t bucketEndTime = fullBucketEndTimeNs;
int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs);
- if (numBucketsForward > 1) {
+
+ // Skip buckets if this is a pulled metric or a pushed metric that is diffed.
+ if (numBucketsForward > 1 && (mIsPulled || mUseDiff)) {
+
VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
// Something went wrong. Maybe the device was sleeping for a long time. It is better
diff --git a/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp b/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp
index db402a0dd658..32cecd3b9dbc 100644
--- a/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp
+++ b/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp
@@ -50,13 +50,13 @@ TEST(MultiConditionTrigger, TestMultipleConditions) {
});
vector<thread> threads;
- vector<bool> done(numConditions, false);
+ vector<int> done(numConditions, 0);
int i = 0;
for (const string& conditionName : conditionNames) {
threads.emplace_back([&done, &conditionName, &trigger, i] {
sleep_for(chrono::milliseconds(3));
- done[i] = true;
+ done[i] = 1;
trigger.markComplete(conditionName);
});
i++;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ddc57474a027..e620f1641acd 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -261,8 +261,9 @@ public class AppOpsManager {
< SystemClock.elapsedRealtime()) {
String stackTrace = getFormattedStackTrace();
try {
+ String packageName = ActivityThread.currentOpPackageName();
sConfig = getService().reportRuntimeAppOpAccessMessageAndGetConfig(
- ActivityThread.currentOpPackageName(), op, stackTrace);
+ packageName == null ? "" : packageName, op, stackTrace);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c8dd4d9d9d51..885ffbac3d30 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -205,6 +205,7 @@ public class PackageParser {
public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
public static final String TAG_USES_SDK = "uses-sdk";
public static final String TAG_USES_SPLIT = "uses-split";
+ public static final String TAG_PROFILEABLE = "profileable";
public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes";
@@ -459,6 +460,9 @@ public class PackageParser {
public final SigningDetails signingDetails;
public final boolean coreApp;
public final boolean debuggable;
+ // This does not represent the actual manifest structure since the 'profilable' tag
+ // could be used with attributes other than 'shell'. Extend if necessary.
+ public final boolean profilableByShell;
public final boolean multiArch;
public final boolean use32bitAbi;
public final boolean extractNativeLibs;
@@ -470,15 +474,13 @@ public class PackageParser {
public final int overlayPriority;
public ApkLite(String codePath, String packageName, String splitName,
- boolean isFeatureSplit,
- String configForSplit, String usesSplitName, boolean isSplitRequired,
- int versionCode, int versionCodeMajor,
- int revisionCode, int installLocation, List<VerifierInfo> verifiers,
- SigningDetails signingDetails, boolean coreApp,
- boolean debuggable, boolean multiArch, boolean use32bitAbi,
- boolean useEmbeddedDex, boolean extractNativeLibs, boolean isolatedSplits,
- String targetPackageName, boolean overlayIsStatic, int overlayPriority,
- int minSdkVersion, int targetSdkVersion) {
+ boolean isFeatureSplit, String configForSplit, String usesSplitName,
+ boolean isSplitRequired, int versionCode, int versionCodeMajor, int revisionCode,
+ int installLocation, List<VerifierInfo> verifiers, SigningDetails signingDetails,
+ boolean coreApp, boolean debuggable, boolean profilableByShell, boolean multiArch,
+ boolean use32bitAbi, boolean useEmbeddedDex, boolean extractNativeLibs,
+ boolean isolatedSplits, String targetPackageName, boolean overlayIsStatic,
+ int overlayPriority, int minSdkVersion, int targetSdkVersion) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -493,6 +495,7 @@ public class PackageParser {
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
this.coreApp = coreApp;
this.debuggable = debuggable;
+ this.profilableByShell = profilableByShell;
this.multiArch = multiArch;
this.use32bitAbi = use32bitAbi;
this.useEmbeddedDex = useEmbeddedDex;
@@ -1573,6 +1576,7 @@ public class PackageParser {
int revisionCode = 0;
boolean coreApp = false;
boolean debuggable = false;
+ boolean profilableByShell = false;
boolean multiArch = false;
boolean use32bitAbi = false;
boolean extractNativeLibs = true;
@@ -1638,6 +1642,10 @@ public class PackageParser {
final String attr = attrs.getAttributeName(i);
if ("debuggable".equals(attr)) {
debuggable = attrs.getAttributeBooleanValue(i, false);
+ if (debuggable) {
+ // Debuggable implies profileable
+ profilableByShell = true;
+ }
}
if ("multiArch".equals(attr)) {
multiArch = attrs.getAttributeBooleanValue(i, false);
@@ -1690,6 +1698,13 @@ public class PackageParser {
minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION);
}
}
+ } else if (TAG_PROFILEABLE.equals(parser.getName())) {
+ for (int i = 0; i < attrs.getAttributeCount(); ++i) {
+ final String attr = attrs.getAttributeName(i);
+ if ("shell".equals(attr)) {
+ profilableByShell = attrs.getAttributeBooleanValue(i, profilableByShell);
+ }
+ }
}
}
@@ -1707,8 +1722,9 @@ public class PackageParser {
return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
configForSplit, usesSplitName, isSplitRequired, versionCode, versionCodeMajor,
revisionCode, installLocation, verifiers, signingDetails, coreApp, debuggable,
- multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs, isolatedSplits,
- targetPackage, overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion);
+ profilableByShell, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs,
+ isolatedSplits, targetPackage, overlayIsStatic, overlayPriority, minSdkVersion,
+ targetSdkVersion);
}
/**
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index d2172d3741d1..c3e9402a389e 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -20,7 +20,6 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
@@ -303,6 +302,7 @@ public class ApkLiteParseUtils {
int revisionCode = 0;
boolean coreApp = false;
boolean debuggable = false;
+ boolean profilableByShell = false;
boolean multiArch = false;
boolean use32bitAbi = false;
boolean extractNativeLibs = true;
@@ -379,6 +379,10 @@ public class ApkLiteParseUtils {
switch (attr) {
case "debuggable":
debuggable = attrs.getAttributeBooleanValue(i, false);
+ if (debuggable) {
+ // Debuggable implies profileable
+ profilableByShell = true;
+ }
break;
case "multiArch":
multiArch = attrs.getAttributeBooleanValue(i, false);
@@ -431,6 +435,13 @@ public class ApkLiteParseUtils {
minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION);
}
}
+ } else if (PackageParser.TAG_PROFILEABLE.equals(parser.getName())) {
+ for (int i = 0; i < attrs.getAttributeCount(); ++i) {
+ final String attr = attrs.getAttributeName(i);
+ if ("shell".equals(attr)) {
+ profilableByShell = attrs.getAttributeBooleanValue(i, profilableByShell);
+ }
+ }
}
}
@@ -445,12 +456,13 @@ public class ApkLiteParseUtils {
overlayPriority = 0;
}
- return input.success(new PackageParser.ApkLite(codePath, packageSplit.first,
- packageSplit.second, isFeatureSplit, configForSplit, usesSplitName, isSplitRequired,
- versionCode, versionCodeMajor, revisionCode, installLocation, verifiers,
- signingDetails, coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex,
- extractNativeLibs, isolatedSplits, targetPackage, overlayIsStatic, overlayPriority,
- minSdkVersion, targetSdkVersion));
+ return input.success(
+ new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second,
+ isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode,
+ versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
+ coreApp, debuggable, profilableByShell, multiArch, use32bitAbi,
+ useEmbeddedDex, extractNativeLibs, isolatedSplits, targetPackage,
+ overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion));
}
public static ParseResult<Pair<String, String>> parsePackageSplitNames(ParseInput input,
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 220ce22ded5c..61e6a05fce37 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -111,6 +111,11 @@ interface IIncrementalService {
void deleteStorage(int storageId);
/**
+ * Permanently disable readlogs reporting for a storage given its ID.
+ */
+ void disableReadLogs(int storageId);
+
+ /**
* Setting up native library directories and extract native libs onto a storage if needed.
*/
boolean configureNativeBinaries(int storageId, in @utf8InCpp String apkFullPath, in @utf8InCpp String libDirRelativePath, in @utf8InCpp String abi, boolean extractNativeLibs);
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 863d86ef88c9..31ccf95ba16f 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -153,6 +153,13 @@ public final class IncrementalFileStorages {
}
/**
+ * Permanently disables readlogs.
+ */
+ public void disableReadLogs() {
+ mDefaultStorage.disableReadLogs();
+ }
+
+ /**
* Resets the states and unbinds storage instances for an installation session.
* TODO(b/136132412): make sure unnecessary binds are removed but useful storages are kept
*/
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 6200a38fe13c..ca6114f29b9c 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -418,6 +418,17 @@ public final class IncrementalStorage {
private static final int INCFS_MAX_ADD_DATA_SIZE = 128;
/**
+ * Permanently disable readlogs collection.
+ */
+ public void disableReadLogs() {
+ try {
+ mService.disableReadLogs(mId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Deserialize and validate v4 signature bytes.
*/
private static void validateV4Signature(@Nullable byte[] v4signatureBytes)
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 397b04e9c023..17620fa3bb4b 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -357,6 +357,19 @@ public class InsetsState implements Parcelable {
return mSources.get(type);
}
+ /**
+ * Returns the source visibility or the default visibility if the source doesn't exist. This is
+ * useful if when treating this object as a request.
+ *
+ * @param type The {@link InternalInsetsType} to query.
+ * @return {@code true} if the source is visible or the type is default visible and the source
+ * doesn't exist.
+ */
+ public boolean getSourceOrDefaultVisibility(@InternalInsetsType int type) {
+ final InsetsSource source = mSources.get(type);
+ return source != null ? source.isVisible() : getDefaultVisibility(type);
+ }
+
public void setDisplayFrame(Rect frame) {
mDisplayFrame.set(frame);
}
@@ -388,20 +401,6 @@ public class InsetsState implements Parcelable {
}
}
- /**
- * A shortcut for setting the visibility of the source.
- *
- * @param type The {@link InternalInsetsType} of the source to set the visibility
- * @param referenceState The {@link InsetsState} for reference
- */
- public void setSourceVisible(@InternalInsetsType int type, InsetsState referenceState) {
- InsetsSource source = mSources.get(type);
- InsetsSource referenceSource = referenceState.mSources.get(type);
- if (source != null && referenceSource != null) {
- source.setVisible(referenceSource.isVisible());
- }
- }
-
public void set(InsetsState other) {
set(other, false /* copySources */);
}
@@ -490,7 +489,7 @@ public class InsetsState implements Parcelable {
}
}
- public static boolean getDefaultVisibility(@InsetsType int type) {
+ public static boolean getDefaultVisibility(@InternalInsetsType int type) {
return type != ITYPE_IME;
}
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index d63ebda5117e..fc8cafdc526c 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -427,6 +427,8 @@ public class ResolverListAdapter extends BaseAdapter {
&& dri.getResolveInfo().targetUserId == UserHandle.USER_CURRENT) {
if (shouldAddResolveInfo(dri)) {
mDisplayList.add(dri);
+ Log.i(TAG, "Add DisplayResolveInfo component: " + dri.getResolvedComponentName()
+ + ", intent component: " + dri.getResolvedIntent().getComponent());
}
}
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 21ca948fa89c..d9ca9c2f87f5 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -1197,6 +1197,10 @@ public class SystemConfig {
addFeature(PackageManager.FEATURE_APP_ENUMERATION, 0);
}
+ if (Build.VERSION.FIRST_SDK_INT >= Build.VERSION_CODES.Q) {
+ addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
+ }
+
for (String featureName : mUnavailableFeatures) {
removeFeature(featureName);
}
diff --git a/core/proto/android/server/blobstoremanagerservice.proto b/core/proto/android/server/blobstoremanagerservice.proto
new file mode 100644
index 000000000000..583b646eb9c7
--- /dev/null
+++ b/core/proto/android/server/blobstoremanagerservice.proto
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package com.android.server.blob;
+
+option java_multiple_files = true;
+
+// The nested messages are used for statsd logging and should be kept in sync with the messages
+// of the same name in frameworks/base/cmds/statsd/src/atoms.proto
+message BlobStatsEventProto {
+ // Blob Committer stats
+ // Keep in sync between:
+ // frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+ // frameworks/base/cmds/statsd/src/atoms.proto
+ message BlobCommitterProto {
+ // Committer app's uid
+ optional int32 uid = 1;
+
+ // Unix epoch timestamp of the commit in milliseconds
+ optional int64 commit_timestamp_millis = 2;
+
+ // Flags of what access types the committer has set for the Blob
+ optional int32 access_mode = 3;
+
+ // Number of packages that have been whitelisted for ACCESS_TYPE_WHITELIST
+ optional int32 num_whitelisted_package = 4;
+ }
+
+ // Blob Leasee stats
+ // Keep in sync between:
+ // frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+ // frameworks/base/cmds/statsd/src/atoms.proto
+ message BlobLeaseeProto {
+ // Leasee app's uid
+ optional int32 uid = 1;
+
+ // Unix epoch timestamp for lease expiration in milliseconds
+ optional int64 lease_expiry_timestamp_millis = 2;
+ }
+
+ // List of Blob Committers
+ // Keep in sync between:
+ // frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+ // frameworks/base/cmds/statsd/src/atoms.proto
+ message BlobCommitterListProto {
+ repeated BlobCommitterProto committer = 1;
+ }
+
+ // List of Blob Leasees
+ // Keep in sync between:
+ // frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+ // frameworks/base/cmds/statsd/src/atoms.proto
+ message BlobLeaseeListProto {
+ repeated BlobLeaseeProto leasee = 1;
+ }
+} \ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f71d4063b847..99b46ecee28f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3534,6 +3534,8 @@
@hide -->
<permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID"
android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" />
+
<!-- Must be required by a {@link android.media.routing.MediaRouteService}
to ensure that only the system can interact with it.
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a1c2450be153..0c8745392f5e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4363,9 +4363,6 @@
<!-- The delete-widget drop target button text -->
<string name="kg_reordering_delete_drop_target_text">Remove</string>
- <!-- Toast message for background started foreground service while-in-use permission restriction feature -->
- <string name="allow_while_in_use_permission_in_fgs">The background started foreground service from <xliff:g id="packageName" example="com.example">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bugreport.</string>
-
<!-- Message shown in dialog when user is attempting to set the music volume above the
recommended maximum level for headphones -->
<string name="safe_media_volume_warning" product="default">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8e1dc8950155..08d1182172f0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4008,9 +4008,6 @@
<java-symbol type="dimen" name="resolver_empty_state_container_padding_top" />
<java-symbol type="dimen" name="resolver_empty_state_container_padding_bottom" />
- <!-- Toast message for background started foreground service while-in-use permission restriction feature -->
- <java-symbol type="string" name="allow_while_in_use_permission_in_fgs" />
-
<java-symbol type="string" name="config_deviceSpecificDisplayAreaPolicyProvider" />
<!-- Whether to expand the lock screen user switcher by default -->
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index a18cfccb6cb2..5a7c87e0235d 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -576,6 +576,10 @@ public final class MediaRouter2Manager {
}
void updatePreferredFeatures(String packageName, List<String> preferredFeatures) {
+ if (preferredFeatures == null) {
+ mPreferredFeaturesMap.remove(packageName);
+ return;
+ }
List<String> prevFeatures = mPreferredFeaturesMap.put(packageName, preferredFeatures);
if ((prevFeatures == null && preferredFeatures.size() == 0)
|| Objects.equals(preferredFeatures, prevFeatures)) {
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index 60934b1e8ddb..495a05b941d6 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -30,11 +30,11 @@
<string name="install_failed_blocked" msgid="8512284352994752094">"यो प्याकेज स्थापना गर्ने क्रममा अवरोध गरियो।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"प्याकेजका रूपमा स्थापना नगरिएको एप विद्यमान प्याकेजसँग मेल खाँदैन।"</string>
<string name="install_failed_incompatible" product="tablet" msgid="6019021440094927928">"एपका रूपमा स्थापना नगरिएको एप तपाईंको ट्याब्लेटसँग मिल्दो छैन।"</string>
- <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"यो एप तपाईंको TV सँग मिल्दो छैन।"</string>
+ <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"यो एप तपाईंको टिभी सँग मिल्दो छैन।"</string>
<string name="install_failed_incompatible" product="default" msgid="7254630419511645826">"एपका रूपमा स्थापना नगरिएको एप तपाईंको फोनसँग मिल्दो छैन।"</string>
<string name="install_failed_invalid_apk" msgid="8581007676422623930">"प्याकेजका रूपमा स्थापना नगरिएको एप अमान्य जस्तो देखिन्छ।"</string>
<string name="install_failed_msg" product="tablet" msgid="6298387264270562442">"तपाईंको ट्याब्लेटमा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
- <string name="install_failed_msg" product="tv" msgid="1920009940048975221">"तपाईंको TV मा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
+ <string name="install_failed_msg" product="tv" msgid="1920009940048975221">"तपाईंको टिभी मा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
<string name="install_failed_msg" product="default" msgid="6484461562647915707">"तपाईंको फोनमा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
<string name="launch" msgid="3952550563999890101">"खोल्नुहोस्"</string>
<string name="unknown_apps_admin_dlg_text" msgid="4456572224020176095">"तपाईंका प्रशासकले अज्ञात स्रोतहरूबाट प्राप्त अनुप्रयोगहरूलाई स्थापना गर्ने अनुमति दिनुहुन्न"</string>
@@ -81,11 +81,11 @@
<string name="message_staging" msgid="8032722385658438567">"एप स्थापना गर्न तयारी गर्दै…"</string>
<string name="app_name_unknown" msgid="6881210203354323926">"अज्ञात"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="6539403649459942547">"तपाईंको सुरक्षाका लागि, तपाईंको ट्याब्लेटलाई यो स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
- <string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"तपाईंको सुरक्षाका लागि, तपाईंको TV लाई यस स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
+ <string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"तपाईंको सुरक्षाका लागि, तपाईंको टिभी लाई यस स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
<string name="untrusted_external_source_warning" product="default" msgid="7279739265754475165">"तपाईंको सुरक्षाका लागि, तपाईंको फोनलाई यो स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"तपाईंको फोन तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको फोनमा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"तपाईंको ट्याब्लेट तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको ट्याब्लेटमा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
- <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तपाईंको TV तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको TV मा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
+ <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तपाईंको टिभी तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको टिभी मा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
<string name="anonymous_source_continue" msgid="4375745439457209366">"जारी राख्नुहोस्"</string>
<string name="external_sources_settings" msgid="4046964413071713807">"सेटिङहरू"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"वेयर एपहरूको स्थापना/स्थापना रद्द गर्दै"</string>
diff --git a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
index 3bf43dd4d1bf..3565b0e3a9ae 100644
--- a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
+++ b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
@@ -30,9 +30,7 @@ import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.DrawableWrapper;
import android.os.RemoteException;
-import android.util.DisplayMetrics;
import android.util.PathParser;
-import android.view.Display;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
@@ -47,6 +45,9 @@ import java.lang.annotation.RetentionPolicy;
*/
public class AdaptiveOutlineDrawable extends DrawableWrapper {
+ private static final float ADVANCED_ICON_CENTER = 50f;
+ private static final float ADVANCED_ICON_RADIUS = 48f;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({TYPE_DEFAULT, TYPE_ADVANCED})
public @interface AdaptiveOutlineIconType {
@@ -61,7 +62,6 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
private int mStrokeWidth;
private Bitmap mBitmap;
private int mType;
- private float mDensity;
public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap) {
super(new AdaptiveIconShapeDrawable(resources));
@@ -83,7 +83,6 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
mPath = new Path(PathParser.createPathFromPathData(
resources.getString(com.android.internal.R.string.config_icon_mask)));
mStrokeWidth = resources.getDimensionPixelSize(R.dimen.adaptive_outline_stroke);
- mDensity = resources.getDisplayMetrics().density;
mOutlinePaint = new Paint();
mOutlinePaint.setColor(getColor(resources, type));
mOutlinePaint.setStyle(Paint.Style.STROKE);
@@ -137,12 +136,7 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
if (mType == TYPE_DEFAULT) {
canvas.drawPath(mPath, mOutlinePaint);
} else {
- final float defaultDensity = getDefaultDisplayDensity(Display.DEFAULT_DISPLAY)
- / (float) DisplayMetrics.DENSITY_DEFAULT;
- final int insetPx =
- Math.round(mInsetPx / (float) (Math.floor(
- (mDensity / defaultDensity) * 100) / 100.0));
- canvas.drawCircle(2 * insetPx, 2 * insetPx, 2 * insetPx - mStrokeWidth,
+ canvas.drawCircle(ADVANCED_ICON_CENTER, ADVANCED_ICON_CENTER, ADVANCED_ICON_RADIUS,
mOutlinePaint);
}
canvas.restoreToCount(count);
diff --git a/packages/SettingsLib/SearchWidget/res/values-el/strings.xml b/packages/SettingsLib/SearchWidget/res/values-el/strings.xml
index 6f5ab78b304b..d50436a29ac1 100644
--- a/packages/SettingsLib/SearchWidget/res/values-el/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-el/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Ρυθμίσεις αναζήτησης"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Αναζήτηση στις ρυθμίσεις"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml b/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml
index 8fa5a84acd79..b68b792acc32 100644
--- a/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Որոնման կարգավորումներ"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Որոնեք կարգավորումներ"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml b/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml
index 85a8d7342827..5fe116e86f94 100644
--- a/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Pesquisa de definições"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Pesquisar nas definições"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml b/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml
index a5313210a6f9..354941d39e12 100644
--- a/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Cilësimet e kërkimit"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Kërko te cilësimet"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml b/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml
index dfd66b28aa7a..560ac1359e5a 100644
--- a/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Налаштування пошуку"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Пошук налаштувань"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
index cb1a75a616f5..90daf11c712d 100644
--- a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Tìm kiếm trong các mục cài đặt"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Tìm trong thông tin cài đặt"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 137116fcac2e..376c2e796f77 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -239,7 +239,7 @@
<string name="keep_screen_on" msgid="1187161672348797558">"Mantendu aktibo"</string>
<string name="keep_screen_on_summary" msgid="1510731514101925829">"Pantaila ez da ezarriko inoiz inaktibo kargatu bitartean"</string>
<string name="bt_hci_snoop_log" msgid="7291287955649081448">"Gaitu Bluetooth HCI miatze-erregistroa"</string>
- <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Hauteman Bluetooth paketeak (aktibatu edo desaktibatu Bluetooth konexioa ezarpena aldatu ostean)."</string>
+ <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Hauteman Bluetooth paketeak (aktibatu edo desaktibatu Bluetooth-a ezarpena aldatu ostean)."</string>
<string name="oem_unlock_enable" msgid="5334869171871566731">"OEM desblokeoa"</string>
<string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Onartu abiarazlea desblokeatzea"</string>
<string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"OEM desblokeoa onartu nahi duzu?"</string>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index de38625afcde..30186831b113 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -22,13 +22,13 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string-array name="wifi_status">
<item msgid="1596683495752107015"></item>
- <item msgid="3288373008277313483">"Scansione in corso..."</item>
- <item msgid="6050951078202663628">"Connessione..."</item>
- <item msgid="8356618438494652335">"Autenticazione..."</item>
- <item msgid="2837871868181677206">"Acquisizione indirizzo IP..."</item>
+ <item msgid="3288373008277313483">"Scansione in corso…"</item>
+ <item msgid="6050951078202663628">"Connessione…"</item>
+ <item msgid="8356618438494652335">"Autenticazione…"</item>
+ <item msgid="2837871868181677206">"Acquisizione indirizzo IP…"</item>
<item msgid="4613015005934755724">"Connessa"</item>
<item msgid="3763530049995655072">"Sospesa"</item>
- <item msgid="7852381437933824454">"Disconnessione..."</item>
+ <item msgid="7852381437933824454">"Disconnessione…"</item>
<item msgid="5046795712175415059">"Disconnessa"</item>
<item msgid="2473654476624070462">"Operazione non riuscita"</item>
<item msgid="9146847076036105115">"Bloccato"</item>
@@ -36,13 +36,13 @@
</string-array>
<string-array name="wifi_status_with_ssid">
<item msgid="5969842512724979061"></item>
- <item msgid="1818677602615822316">"Scansione in corso..."</item>
- <item msgid="8339720953594087771">"Connessione a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
- <item msgid="3028983857109369308">"Autenticazione con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
- <item msgid="4287401332778341890">"Acquisizione indirizzo IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+ <item msgid="1818677602615822316">"Scansione in corso…"</item>
+ <item msgid="8339720953594087771">"Connessione a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="3028983857109369308">"Autenticazione con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="4287401332778341890">"Acquisizione indirizzo IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="1043944043827424501">"Connessa a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
<item msgid="7445993821842009653">"Sospesa"</item>
- <item msgid="1175040558087735707">"Disconnessione da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+ <item msgid="1175040558087735707">"Disconnessione da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="699832486578171722">"Disconnessa"</item>
<item msgid="522383512264986901">"Operazione non riuscita"</item>
<item msgid="3602596701217484364">"Bloccato"</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index 38eeda245616..898796828131 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -22,10 +22,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.hardware.usb.IUsbManager;
import android.net.Uri;
+import android.os.Environment;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -146,10 +148,23 @@ public class AppUtils {
/**
* Returns a boolean indicating whether a given package is a mainline module.
*/
- public static boolean isMainlineModule(Context context, String packageName) {
- final PackageManager pm = context.getPackageManager();
+ public static boolean isMainlineModule(PackageManager pm, String packageName) {
+ // Check if the package is listed among the system modules.
try {
- return pm.getModuleInfo(packageName, 0 /* flags */) != null;
+ pm.getModuleInfo(packageName, 0 /* flags */);
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ //pass
+ }
+
+ try {
+ final PackageInfo pkg = pm.getPackageInfo(packageName, 0 /* flags */);
+ // Check if the package is contained in an APEX. There is no public API to properly
+ // check whether a given APK package comes from an APEX registered as module.
+ // Therefore we conservatively assume that any package scanned from an /apex path is
+ // a system package.
+ return pkg.applicationInfo.sourceDir.startsWith(
+ Environment.getApexDirectory().getAbsolutePath());
} catch (PackageManager.NameNotFoundException e) {
return false;
}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index c9e1944bd6f2..51f69a95e163 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -237,4 +237,7 @@
<!-- Default for Settings.Secure.AWARE_LOCK_ENABLED -->
<bool name="def_aware_lock_enabled">false</bool>
+
+ <!-- Default for setting for Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED -->
+ <bool name="def_hdmiControlAutoDeviceOff">false</bool>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 94509ddcc407..b95d34f2966b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3513,7 +3513,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 190;
+ private static final int SETTINGS_VERSION = 191;
private final int mUserId;
@@ -4867,6 +4867,21 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 190;
}
+ if (currentVersion == 190) {
+ // Version 190: get HDMI auto device off from overlay
+ final SettingsState globalSettings = getGlobalSettingsLocked();
+ final Setting currentSetting = globalSettings.getSettingLocked(
+ Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED);
+ if (currentSetting.isNull()) {
+ globalSettings.insertSettingLocked(
+ Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
+ getContext().getResources().getBoolean(
+ R.bool.def_hdmiControlAutoDeviceOff) ? "1" : "0",
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ currentVersion = 191;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index 18ab908945ac..02531f2fb6e7 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -21,7 +21,7 @@
<string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generazione segnalazione di bug <xliff:g id="ID">#%d</xliff:g> in corso"</string>
<string name="bugreport_finished_title" msgid="4429132808670114081">"Segnalazione di bug <xliff:g id="ID">#%d</xliff:g> acquisita"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Aggiunta di dettagli alla segnalazione di bug"</string>
- <string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi..."</string>
+ <string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi…"</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"La segnalazione di bug comparirà a breve sul telefono"</string>
<string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Seleziona per condividere la segnalazione di bug"</string>
<string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tocca per condividere la segnalazione di bug"</string>
diff --git a/packages/Shell/res/values-ky/strings.xml b/packages/Shell/res/values-ky/strings.xml
index 969e9ed0654e..3567ac276e63 100644
--- a/packages/Shell/res/values-ky/strings.xml
+++ b/packages/Shell/res/values-ky/strings.xml
@@ -29,7 +29,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Мүчүлүштүк тууралуу билдирүүңүздү скриншотсуз бөлүшүү үчүн таптап коюңуз же скриншот даяр болгуча күтө туруңуз"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Мүчүлүштүк тууралуу билдирүүңүздү скриншотсуз бөлүшүү үчүн таптап коюңуз же скриншот даяр болгуча күтө туруңуз"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Мүчүлүштүктөр тууралуу билдирүүлөрдө тутумдун ар кандай таржымалдарынан алынган дайындар, ошондой эле купуя маалымат камтылышы мүмкүн (мисалы, жайгашкан жер сыяктуу). Мындай билдирүүлөрдү бир гана ишеничтүү адамдар жана колдонмолор менен бөлүшүңүз."</string>
- <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Экинчи көрсөтүлбөсүн"</string>
+ <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Экинчи көрүнбөсүн"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Мүчүлүштүктөрдү кабарлоо"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Мүчүлүштүк тууралуу кабарлаган файл окулбай койду"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Мүчүлүштүктөр жөнүндө кабардын чоо-жайы zip файлына кошулбай койду"</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 80deb34656a0..fe460e38dc0b 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -48,7 +48,7 @@
<string name="keyguard_permanent_disabled_sim_instructions" msgid="2490584154727897806">"La scheda SIM è stata disattivata definitivamente.\n Contatta il fornitore del tuo servizio wireless per ricevere un\'altra scheda SIM."</string>
<string name="keyguard_sim_locked_message" msgid="4343544458476911044">"La SIM è bloccata."</string>
<string name="keyguard_sim_puk_locked_message" msgid="6253830777745450550">"La SIM è bloccata tramite PUK."</string>
- <string name="keyguard_sim_unlock_progress_dialog_message" msgid="2394023844117630429">"Sblocco SIM..."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="2394023844117630429">"Sblocco SIM…"</string>
<string name="keyguard_accessibility_pin_area" msgid="7403009340414014734">"Area PIN"</string>
<string name="keyguard_accessibility_password" msgid="3524161948484801450">"Password del dispositivo"</string>
<string name="keyguard_accessibility_sim_pin_area" msgid="6272116591533888062">"Area PIN SIM"</string>
@@ -77,7 +77,7 @@
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"La SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" non è attiva al momento. Inserisci il codice PUK per continuare. Contatta l\'operatore per avere informazioni dettagliate."</string>
<string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Inserisci il codice PIN desiderato"</string>
<string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Conferma il codice PIN desiderato"</string>
- <string name="kg_sim_unlock_progress_dialog_message" msgid="4251352015304070326">"Sblocco SIM..."</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="4251352015304070326">"Sblocco SIM…"</string>
<string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Il PIN deve essere di 4-8 numeri."</string>
<string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Il codice PUK dovrebbe avere almeno otto numeri."</string>
<string name="kg_invalid_puk" msgid="1774337070084931186">"Inserisci di nuovo il codice PUK corretto. Ripetuti tentativi comportano la disattivazione definitiva della scheda SIM."</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index fd475b9ee4de..bfa21071d815 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -522,8 +522,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"محو الكل"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"إدارة"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"السجلّ"</string>
- <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
- <skip />
+ <string name="notification_section_header_incoming" msgid="850925217908095197">"الإشعارات الجديدة"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"صامت"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"الإشعارات"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"المحادثات"</string>
@@ -608,7 +607,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"تم تثبيت الشاشة على التطبيق"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"نظرة عامة\" لإزالة التثبيت."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"الشاشة الرئيسية\" لإزالة التثبيت."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. مرّر الشاشة بسرعة للأعلى مع الاستمرار لإزالة تثبيت الشاشة."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"يؤدي هذا الإجراء إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. لإلغاء تثبيت الشاشة على هذا التطبيق، اسحب بسرعة للأعلى مع إبقاء الإصبع على الشاشة."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار زر \"نظرة عامة\" لإزالة التثبيت."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار زر \"الشاشة الرئيسية\" لإزالة التثبيت."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"يمكن الوصول إلى البيانات الشخصية (مثلاً جهات الاتصال ومحتوى الرسائل الإلكترونية)"</string>
@@ -1023,8 +1022,7 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"الانتقال إلى أعلى اليسار"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نقل إلى أسفل يمين الشاشة"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نقل إلى أسفل اليسار"</string>
- <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
- <skip />
+ <string name="bubble_dismiss_text" msgid="1314082410868930066">"إغلاق فقاعة المحادثة"</string>
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"عدم عرض المحادثة كفقاعة محادثة"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"الدردشة باستخدام فقاعات المحادثات"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"تظهر المحادثات الجديدة كرموز عائمة أو كفقاعات. انقر لفتح فقاعة المحادثة، واسحبها لتحريكها."</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index aad8eec3e35e..7a9fecad5f9d 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"অ্যাপ পিন করা হয়েছে"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ফিরুন এবং ওভারভিউ স্পর্শ করে ধরে থাকুন।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"এর ফলে আপনি এটি আনপিন না করা পর্যন্ত এটি দেখানো হতে থাকবে। আনপিন করতে \"ফিরে যান\" এবং \"হোম\" বোতামদুটি ট্যাপ করে ধরে রাখুন।"</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"এর ফলে আপনি আনপিন না করা পর্যন্ত এটি দেখানো হতে থাকবে। আনপিন করার জন্য উপরের দিকে সোয়াইপ করে ধরে থাকুন"</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"এর ফলে আপনি আনপিন না করা পর্যন্ত এটি দেখানো হবে। আনপিন করার জন্য উপরের দিকে সোয়াইপ করে ধরে থাকুন।"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ওভারভিউ স্পর্শ করে ধরে থাকুন৷"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"এর ফলে আপনি এটি আনপিন না করা পর্যন্ত এটি দেখানো হতে থাকবে। আনপিন করতে \"হোম\" বোতামটি ট্যাপ করে ধরে রাখুন।"</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ব্যক্তিগত তথ্য অ্যাক্সেস করা যেতে পারে (যেমন, পরিচিতি ও ইমেল কন্টেন্ট)।"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 6cdc1d79b00d..49fae626fa5a 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -601,7 +601,7 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Na ovaj način ekran ostaje prikazan dok ga ne otkačite. Prevucite prema gore i držite da otkačite."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Pregled."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Na ovaj način ekran ostaje prikazan dok ga ne otkačite. Da okačite ekran, dodirnite ili držite dugme Početna."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Lični podaci mogu biti dostupni (kao što su kontakti i sadržaj e-pošte)."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Lični podaci mogu biti dostupni (naprimjer kontakti i sadržaj e-pošte)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Zakačena aplikacija može otvoriti druge aplikacije."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Dodirnite i držite dugmad Nazad i Pregled da otkačite ovu aplikaciju"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Dodirnite i držite dugmad Nazad i Početni ekran da otkačite ovu aplikaciju"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 22a0e05e2ea5..f1bbbff3d7b6 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -595,10 +595,10 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"Appen er fastgjort"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage og Overblik, og hold fingeren nede for at frigøre skærmen."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Tilbage og Startskærm nede for at frigøre skærmen."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Dette fastholder skærmen i visningen, indtil du frigør den. Stryg opad, og hold fingeren nede for at frigøre den."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Dette fastholder appen på skærmen, indtil du frigør den. Stryg opad, og hold fingeren nede for at frigøre den."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage, og hold fingeren nede for at frigøre skærmen."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Startskærm nede for at frigøre skærmen."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personoplysninger er muligvis tilgængelige (f.eks. kontakter og mailindhold)."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Der kan stadig være adgang til personoplysninger (f.eks. kontakter og mailindhold)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"En fastgjort app kan åbne andre apps."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Du kan frigøre denne app ved at holde knapperne Tilbage og Oversigt nede"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Du kan frigøre denne app ved at holde knapperne Tilbage og Hjem nede"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 171b6f61cff4..ac20c8477d47 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up &amp; hold to unpin."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up and hold to unpin."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"This keeps it in view until you unpin. Touch &amp; hold Home to unpin."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personal data may be accessible (such as contacts and email content)."</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 5fb6236d6dcd..233664e5fbc7 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up &amp; hold to unpin."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up and hold to unpin."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"This keeps it in view until you unpin. Touch &amp; hold Home to unpin."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personal data may be accessible (such as contacts and email content)."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 171b6f61cff4..ac20c8477d47 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up &amp; hold to unpin."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up and hold to unpin."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"This keeps it in view until you unpin. Touch &amp; hold Home to unpin."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personal data may be accessible (such as contacts and email content)."</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 171b6f61cff4..ac20c8477d47 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up &amp; hold to unpin."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up and hold to unpin."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"This keeps it in view until you unpin. Touch &amp; hold Home to unpin."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personal data may be accessible (such as contacts and email content)."</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 8e244a2a37ae..cb6f7967d3e8 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -279,12 +279,12 @@
<string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"Desaktibatu egin da ez molestatzeko modua."</string>
<string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"Aktibatu egin da ez molestatzeko modua."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth-a."</string>
- <string name="accessibility_quick_settings_bluetooth_off" msgid="3795983516942423240">"Bluetooth konexioa desaktibatuta dago."</string>
- <string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth konexioa aktibatuta dago."</string>
+ <string name="accessibility_quick_settings_bluetooth_off" msgid="3795983516942423240">"Bluetooth bidezko konexioa desaktibatuta dago."</string>
+ <string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth bidezko konexioa aktibatuta dago."</string>
<string name="accessibility_quick_settings_bluetooth_connecting" msgid="7362294657419149294">"Bluetooth bidez konektatzen ari da."</string>
<string name="accessibility_quick_settings_bluetooth_connected" msgid="5237625393869747261">"Bluetooth bidez konektatuta dago."</string>
- <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="3344226652293797283">"Bluetooth konexioa desaktibatu egin da."</string>
- <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"Bluetooth konexioa aktibatu egin da."</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="3344226652293797283">"Bluetooth bidezko konexioa desaktibatu egin da."</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"Bluetooth bidezko konexioa aktibatu egin da."</string>
<string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"Kokapena hautemateko aukera desaktibatuta dago."</string>
<string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"Kokapena hautemateko aukera aktibatuta dago."</string>
<string name="accessibility_quick_settings_location_changed_off" msgid="5132776369388699133">"Kokapena hautemateko aukera desaktibatu egin da."</string>
@@ -595,11 +595,11 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikazioa ainguratuta dago"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Atzera\" eta \"Ikuspegi orokorra\" botoiak."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Atzera eta Hasiera botoiak."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Hasiera botoia."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, pasatu hatza gora eduki ezazu sakatuta."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Ikuspegi orokorra\" botoia."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Hasiera botoia."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Baliteke datu pertsonalak atzitu ahal izatea (adibidez, kontaktuak eta posta elektronikoko edukia)."</string>
- <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Baliteke ainguratutako aplikazioak beste aplikazio batzuk irekitzeko gai izatea."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Baliteke ainguratutako aplikazioa beste aplikazio batzuk irekitzeko gai izatea."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Aplikazioari aingura kentzeko, eduki sakatuta Atzera eta Ikuspegi orokorra botoiak"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Aplikazioari aingura kentzeko, eduki sakatuta Atzera eta Hasiera botoiak"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Aplikazioari aingura kentzeko, arrastatu aplikazioa gora eta eduki ezazu sakatuta"</string>
@@ -959,7 +959,7 @@
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> (<xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>)"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi konexioa desaktibatuta dago"</string>
- <string name="bt_is_off" msgid="7436344904889461591">"Bluetooth konexioa desaktibatuta dago"</string>
+ <string name="bt_is_off" msgid="7436344904889461591">"Bluetooth bidezko konexioa desaktibatuta dago"</string>
<string name="dnd_is_off" msgid="3185706903793094463">"Ez molestatzeko modua desaktibatuta dago"</string>
<string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Ez molestatzeko modua aktibatu du arau automatiko batek (<xliff:g id="ID_1">%s</xliff:g>)."</string>
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Ez molestatzeko modua aktibatu du aplikazio batek (<xliff:g id="ID_1">%s</xliff:g>)."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 4ebfa797edf4..ae98244cf415 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"برنامه پین شده است"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"تا زمانی که پین را بردارید، در نما نگه‌داشته می‌شود. برای برداشتن پین، «برگشت» و «نمای کلی» را لمس کنید و نگه‌دارید."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"تا برداشتن پین، در نما نگه‌داشته می‌شود. برای برداشتن پین، «برگشت» و «صفحه اصلی» را لمس کنید و نگه‌دارید."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"تا برداشتن پین، در نما نگه‌داشته می‌شود. برای برداشتن پین، از پایین صفحه تند به‌طرف بالا بکشید و نگه‌دارید."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"به این ترتیب تا زمانی پین آن را برندارید قابل‌مشاهده است. برای برداشتن پین، از پایین صفحه تند به‌طرف بالا بکشید و نگه دارید."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"تا زمانی که پین را بردارید، در نما نگه‌داشته می‌شود. برای برداشتن پین، «نمای کلی» را لمس کنید و نگه‌دارید."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"تا برداشتن پین، در نما نگه‌داشته می‌شود. برای برداشتن پین، «صفحه اصلی» را لمس کنید و نگه‌دارید."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ممکن است داده‌های شخصی (مانند مخاطبین و محتوای ایمیل) در دسترس باشد."</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index c4b8ae2ea421..473f6de00c89 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -510,8 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"બધુ સાફ કરો"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"મેનેજ કરો"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ઇતિહાસ"</string>
- <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
- <skip />
+ <string name="notification_section_header_incoming" msgid="850925217908095197">"નવા"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"સાઇલન્ટ"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"નોટિફિકેશન"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"વાતચીત"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 22f908011455..00389073626b 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -595,12 +595,12 @@
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करें"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"आउटपुट डिवाइस बदलें"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ऐप्लिकेशन पिन किया गया है"</string>
- <string name="screen_pinning_description" msgid="8699395373875667743">"इससे वह तब तक दिखता रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' को दबाकर रखें."</string>
+ <string name="screen_pinning_description" msgid="8699395373875667743">"इससे वह तब तक दिखता रहता है, जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' को दबाकर रखें."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम और वापस जाएं वाले बटन को दबाकर रखें."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"इससे ऐप्लिकेशन की स्क्रीन तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं करते. अनपिन करने के लिए ऊपर स्वाइप करें और स्क्रीन दबाकर रखें."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"इससे ऐप्लिकेशन की स्क्रीन तब तक दिखाई देती है, जब तक आप उसे अनपिन नहीं करते. अनपिन करने के लिए ऊपर स्वाइप करें और स्क्रीन दबाकर रखें."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"इससे वह तब तक दिखता रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'खास जानकारी\' को दबाकर रखें."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम बटन को दबाकर रखें."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"निजी डेटा ऐक्सेस किया जा सकता है. जैसे कि संपर्क और ईमेल का कॉन्टेंट."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"निजी डेटा ऐक्सेस किया जा सकता है, जैसे कि संपर्क और ईमेल का कॉन्टेंट."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"पिन किए गए ऐप्लिकेशन से दूसरे ऐप्लिकेशन भी खोले जा सकते हैं."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"इस ऐप्लिकेशन को अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' बटन को साथ-साथ दबाकर रखें"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"इस ऐप्लिकेशन को अनपिन करने के लिए, \'होम\' और \'वापस जाएं\' बटन को साथ-साथ दबाकर रखें"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 0dc7256f985d..64e7011a63a9 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"Az alkalmazás ki van tűzve"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és az Áttekintés lehetőséget."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és a Kezdőképernyő elemet."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz csúsztasson fel, és tartsa ujját a képernyőn."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz csúsztassa fel és tartsa ujját a képernyőn."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva az Áttekintés lehetőséget."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Kezdőképernyő elemet."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Bizonyos személyes adatok (például a névjegyek és az e-mailek tartalma) hozzáférhetők lehetnek."</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index dd6c363abb4c..72fac719f1f1 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikasi dipasangi pin"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh lama tombol Kembali dan Ringkasan untuk melepas pin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh lama tombol Kembali dan Beranda untuk melepas pin."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ini akan terus ditampilkan sampai Anda melepas pin. Geser ke atas &amp; tahan untuk melepas pin."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Aplikasi akan terus ditampilkan sampai pin dilepas. Geser ke atas dan tahan untuk lepas pin."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh lama tombol Ringkasan untuk melepas pin."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh lama tombol Beranda untuk melepas pin."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data pribadi dapat diakses (seperti kontak dan konten email)."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 21434bac9807..b90ae3e5834a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -592,14 +592,14 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"attiva"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disattiva"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Cambia dispositivo di uscita"</string>
- <string name="screen_pinning_title" msgid="9058007390337841305">"L\'app è bloccata"</string>
+ <string name="screen_pinning_title" msgid="9058007390337841305">"L\'app è bloccata su schermo"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Indietro e Panoramica."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tocca e tieni premuto Indietro e Home."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Mantiene la visualizzazione fino allo sblocco. Scorri verso l\'alto e tieni premuto per sbloccare."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Rimarrà visibile finché non viene sbloccata. Scorri verso l\'alto e tieni premuto per sbloccarla."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Panoramica."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tocca e tieni premuto Home."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"I dati personali potrebbero essere accessibili (ad esempio i contatti e i contenuti delle email)."</string>
- <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Un\'app bloccata potrebbe aprire altre app."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"L\'app bloccata su schermo potrebbe aprire altre app."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Per sbloccare questa app, tocca e tieni premuti i pulsanti Indietro e Panoramica"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Per sbloccare questa app, tocca e tieni premuti i pulsanti Indietro e Home"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Per sbloccare questa app, scorri verso l\'alto e tieni premuto"</string>
@@ -1002,7 +1002,7 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sposta in alto a destra"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sposta in basso a sinistra"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sposta in basso a destra"</string>
- <string name="bubble_dismiss_text" msgid="1314082410868930066">"Ignora bolle"</string>
+ <string name="bubble_dismiss_text" msgid="1314082410868930066">"Ignora bolla"</string>
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Non utilizzare bolle per la conversazione"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatta utilizzando le bolle"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Le nuove conversazioni vengono visualizzate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 24dae2745b8c..9d2d0cc973aa 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -601,7 +601,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"האפליקציה מוצמדת"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\' כדי לבטל את ההצמדה."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"נשאר בתצוגה עד לביטול ההצמדה. יש להחליק למעלה ולהחזיק כדי לבטל הצמדה."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"היא תמשיך להופיע עד שההצמדה תבוטל. כדי לבטל את ההצמדה, יש להחליק למעלה ולהחזיק."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'סקירה\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'דף הבית\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ייתכן שתתאפשר גישה למידע אישי (כמו אנשי קשר ותוכן מהאימייל)."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 0f248a1332b2..4f6c7858379c 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -603,7 +603,7 @@
<string name="screen_pinning_toast" msgid="8177286912533744328">"このアプリの固定を解除するには [戻る] ボタンと [最近] ボタンを長押しします"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"このアプリの固定を解除するには [戻る] ボタンと [ホーム] ボタンを長押しします"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"このアプリの固定を解除するには、上にスワイプして長押しします"</string>
- <string name="screen_pinning_positive" msgid="3285785989665266984">"はい"</string>
+ <string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"いいえ"</string>
<string name="screen_pinning_start" msgid="7483998671383371313">"固定したアプリ"</string>
<string name="screen_pinning_exit" msgid="4553787518387346893">"固定を解除したアプリ"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 9b8fa78213bc..74f43e870da7 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -598,7 +598,7 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн өйдө сүрүп, коё бербей басып туруңуз."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Карап чыгуу\" баскычын басып, кармап туруңуз."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Башкы бет\" баскычын басып, кармап туруңуз."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Байланыштар жана электрондук почталардын мазмуну сыяктуу жеке дайындар ачык болушу мүмкүн."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Байланыштар жана электрондук почталардын мазмуну сыяктуу жеке маалымат ачык болушу мүмкүн."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Кадалган колдонмо башка колдонмолорду ача алат."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Бул колдонмону бошотуу үчүн \"Артка\" жана \"Назар салуу\" баскычтарын басып, кармап туруңуз"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Бул колдонмону бошотуу үчүн \"Артка\" жана \"Башкы бет\" баскычтарын басып, кармап туруңуз"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 47353fd85e03..0fe47aab6e7c 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -598,7 +598,7 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ນີ້ຈະເຮັດໃຫ້ມັນຢູ່ໃນມຸມມອງຈົນກວ່າທ່ານຈະເຊົາປັກໝຸດ. ປັດຂຶ້ນຄ້າງໄວ້ເພື່ອເຊົາປັກໝຸດ."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກມຸດ. ໃຫ້ແຕະປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກມຸດ."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກໝຸດ. ໃຫ້ແຕະປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກໝຸດ."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ອາດສາມາດເຂົ້າເຖິງຂໍ້ມູນສ່ວນຕົວໄດ້ (ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ເນື້ອຫາອີເມວ)"</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ອາດສາມາດເຂົ້າເຖິງຂໍ້ມູນສ່ວນຕົວໄດ້ (ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ເນື້ອຫາອີເມວ)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ແອັບທີ່ປັກໝຸດໄວ້ອາດເປີດແອັບອື່ນ."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"ເພື່ອຍົກເລີກການປັກໝຸດແອັບນີ້, ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ເພື່ອຍົກເລີກການປັກໝຸດແອັບນີ້, ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 0b629a329336..09e7ff17714f 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -592,20 +592,20 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"овозможи"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"оневозможи"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Префрлете го излезниот уред"</string>
- <string name="screen_pinning_title" msgid="9058007390337841305">"Апликацијата е прикачена"</string>
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Апликацијата е закачена"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Назад“ и „Краток преглед“ за откачување."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Назад“ и „Почетен екран“ за откачување."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ќе се гледа сѐ додека не го откачите. Лизгајте нагоре и задржете за откачување."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ќе се гледа сѐ додека не ја откачите. Повлечете нагоре и задржете за откачување."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Краток преглед“ за откачување."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Почетен екран“ за откачување."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Личните податоци може да се пристапни (како контакти и содржини од е-пошта)."</string>
- <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Прикачените апликации може да отворат други апликации."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Може да бидат достапни лични податоци (како контакти и содржини од е-пошта)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Закачената апликација може да отвора други апликации."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"За откачување на апликацијава, допрете и држете на копчињата „Назад“ и „Преглед“"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"За откачување на апликацијава, допрете и држете на копчињата „Назад“ и „Почетен екран“"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"За откачување на апликацијава, повлечете нагоре и држете"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Сфатив"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Не, фала"</string>
- <string name="screen_pinning_start" msgid="7483998671383371313">"Апликацијата е прикачена"</string>
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Апликацијата е закачена"</string>
<string name="screen_pinning_exit" msgid="4553787518387346893">"Апликацијата е откачена"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Сокриј <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Ќе се појави повторно следниот пат кога ќе го вклучите во поставки."</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index b24518daa31b..e4d4ba407732 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1003,8 +1003,7 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
- <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
- <skip />
+ <string name="bubble_dismiss_text" msgid="1314082410868930066">"ബബിൾ ഡിസ്മിസ് ചെയ്യൂ"</string>
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"സംഭാഷണം ബബിൾ ചെയ്യരുത്"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"ബബിളുകൾ ഉപയോഗിച്ച് ചാറ്റ് ചെയ്യുക"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"പുതിയ സംഭാഷണങ്ങൾ ഫ്ലോട്ടിംഗ് ഐക്കണുകളോ ബബിളുകളോ ആയി ദൃശ്യമാവുന്നു. ബബിൾ തുറക്കാൻ ടാപ്പ് ചെയ്യൂ. ഇത് നീക്കാൻ വലിച്ചിടുക."</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 9587e71e6136..d49f46d840b2 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1003,8 +1003,7 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"वर उजवीकडे हलवा"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"तळाशी डावीकडे हलवा"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"तळाशी उजवीकडे हलवा"</string>
- <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
- <skip />
+ <string name="bubble_dismiss_text" msgid="1314082410868930066">"बबल डिसमिस करा"</string>
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"संभाषणाला बबल करू नका"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"बबल वापरून चॅट करा"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"नवीन संभाषणे फ्लोटिंग आयकन किंवा बबल म्हणून दिसतात. बबल उघडण्यासाठी टॅप करा. हे हलवण्यासाठी ड्रॅग करा."</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 8c06f6768590..eaf4157ff4e1 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -598,7 +598,7 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"သင်က ပင်မဖြုတ်မချင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ။"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"သင်ပင်မဖြုတ်မချင်း ၎င်းကိုပြသထားပါမည်။ ပင်ဖြုတ်ရန် Overview ကိုထိပြီး ဖိထားပါ။"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"သင်က ပင်မဖြုတ်မချင်း ၎င်းကိုပြသထားပါမည်။ ပင်ဖြုတ်ရန် \'ပင်မ\' ခလုတ်ကို တို့၍ဖိထားပါ။"</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"(အဆက်အသွယ်နှင့် အီးမေးလ်အကြောင်းအရာများကဲ့သို့) ကိုယ်ရေးကိုယ်တာ ဒေတာများကို အသုံးပြုနိုင်ပါသည်။"</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ကိုယ်ရေးကိုယ်တာ ဒေတာများ (အဆက်အသွယ်နှင့် အီးမေးလ် အကြောင်းအရာများကဲ့သို့) ကို အသုံးပြုနိုင်ပါသည်။"</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ပင်ထိုးထားသည့်အက်ပ်က အခြားအက်ပ်များကို ဖွင့်နိုင်သည်။"</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"ဤအက်ပ်ကိုပင်ဖြုတ်ရန် \'နောက်သို့\' နှင့် \'အနှစ်ချုပ်\' ခလုတ်များကို ထိ၍နှိပ်ထားပါ"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ဤအက်ပ်ကိုပင်ဖြုတ်ရန် \'နောက်သို့\' နှင့် \'ပင်မ\' ခလုတ်တို့ကို ထိ၍နှိပ်ထားပါ"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 812477ad33d2..fda85ccb542c 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -596,7 +596,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"एप पिन गरिएको छ"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र गृह नामक बटनहरूलाई छोइराख्नुहोस्।"</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"तपाईंले अनपिन नगरेसम्म यस कार्यले यसलाई दृश्यमा राख्छ। अनपिन गर्न माथितिर स्वाइप गरी होल्ड गर्नुहोस्।"</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"तपाईंले यो एप अनपिन नगरेसम्म यो एप यहाँ देखिइरहने छ। अनपिन गर्न माथितिर स्वाइप गरी होल्ड गर्नुहोस्।"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न गृह नामक बटनलाई छोइराख्नुहोस्।"</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"स्क्रिनमा व्यक्तिगत डेटा (जस्तै सम्पर्क ठेगाना र इमेलको सामग्री) देखिन सक्छ।"</string>
@@ -1003,8 +1003,7 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"सिरानमा दायाँतिर सार्नुहोस्"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"पुछारमा बायाँतिर सार्नुहोस्"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"पुछारमा दायाँतिर सार्नुहोस्"</string>
- <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
- <skip />
+ <string name="bubble_dismiss_text" msgid="1314082410868930066">"बबल खारेज गर्नुहोस्"</string>
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"वार्तालाप बबलको रूपमा नदेखाइयोस्"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"बबलहरू प्रयोग गरी कुराकानी गर्नुहोस्"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"नयाँ वार्तालापहरू तैरने आइकन वा बबलका रूपमा देखिन्छन्। बबल खोल्न ट्याप गर्नुहोस्। बबल सार्न सो बबललाई ड्र्याग गर्नुहोस्।"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 4e4cc773d69f..87f072b9e7dd 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"App is vastgezet"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Overzicht en houd deze vast om het scherm los te maken."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Home en houd deze vast om het scherm los te maken."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Zo blijft het scherm zichtbaar totdat je dit losmaakt. Veeg omhoog en houd vast om los te maken."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Zo blijft het scherm zichtbaar totdat je dit losmaakt. Swipe omhoog en houd vast om los te maken."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Overzicht en houd dit vast om het scherm los te maken."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Home en houd dit vast om het scherm los te maken."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Persoonlijke informatie kan toegankelijk zijn (zoals contacten en e-mailcontent)."</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 13bc85ae689d..426bd2ec1ada 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -596,7 +596,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"ଆପକୁ ପିନ୍ କରାଯାଇଛି"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବାକୁ ସ୍ପର୍ଶ କରି ଧରିରଖନ୍ତୁ ଓ ଦେଖନ୍ତୁ।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବା ପାଇଁ ହୋମ୍ ଓ ବ୍ୟାକ୍ ବଟନ୍‌କୁ ଧରିରଖନ୍ତୁ।"</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ଆପଣ ଅନ୍‌ପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଯାଉଥିବ। ଅନ୍‌ପିନ୍ କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍‌ କରି ଧରି ରଖନ୍ତୁ"</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ଆପଣ ଅନ୍‌ପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଯାଉଥିବ। ଅନ୍‌ପିନ୍ କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍‌ କରି ଧରି ରଖନ୍ତୁ।"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବାକୁ ସ୍ପର୍ଶ କରନ୍ତୁ ଏବଂ ଓଭରଭ୍ୟୁକୁ ଧରିରଖନ୍ତୁ।"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବା ପର୍ଯ୍ୟନ୍ତ ହୋମ୍‌କୁ ଦାବିଧରନ୍ତୁ।"</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ବ୍ୟକ୍ତିଗତ ଡାଟାକୁ ଆକ୍ସେସ୍ କରାଯାଇପାରେ (ଯେପରିକି ଯୋଗାଯୋଗଗୁଡ଼ିକ ଏବଂ ଇମେଲ୍ ବିଷୟବସ୍ତୁ)।"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index fe4dfb2fba54..ccafc49614bb 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -510,8 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ਇਤਿਹਾਸ"</string>
- <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
- <skip />
+ <string name="notification_section_header_incoming" msgid="850925217908095197">"ਨਵਾਂ"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"ਸ਼ਾਂਤ"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"ਸੂਚਨਾਵਾਂ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ਗੱਲਾਂਬਾਤਾਂ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index b2aaa05724e1..cf63b1122da7 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -516,8 +516,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Usuń wszystkie"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Zarządzaj"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
- <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
- <skip />
+ <string name="notification_section_header_incoming" msgid="850925217908095197">"Nowe"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Ciche"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Powiadomienia"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Rozmowy"</string>
@@ -605,7 +604,7 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ekran będzie widoczny, dopóki go nie odepniesz. Przesuń palcem w górę i przytrzymaj, by odpiąć."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Przegląd."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, naciśnij i przytrzymaj Ekran główny."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dane osobowe mogą być dostępne (np. kontakty czy treść e-maili)."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dane osobowe (np. kontakty czy treść e-maili) mogą być dostępne."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Przypięta aplikacja może otwierać inne aplikacje."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Aby odpiąć tę aplikację, naciśnij i przytrzymaj przyciski Wstecz oraz Przegląd"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Aby odpiąć tę aplikację, naciśnij i przytrzymaj przyciski Wstecz oraz Ekran główny"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 24e7912be621..55b5af121f37 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"A app está fixada"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Vista geral para soltar."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Página inicial para soltar."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Esta opção mantém o item visível até o soltar. Deslize rapidamente para cima e mantenha o gesto para soltar."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Esta opção mantém o item visível até o soltar. Deslize rapidamente para cima e mantenha pressionado para soltar."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Vista geral para soltar."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Página inicial para soltar."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Os dados pessoais podem ficar acessíveis (tais como contactos e conteúdo do email)."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 6b18dc41932f..0f0f598cebf4 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -598,7 +598,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplicația este fixată"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Recente pentru a anula fixarea."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Acasă pentru a anula fixarea."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Astfel rămâne afișat până anulați fixarea. Glisați în sus și țineți apăsat pentru a anula fixarea."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Astfel rămâne afișată până anulați fixarea. Glisați în sus și țineți apăsat pentru a anula fixarea."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Recente pentru a anula fixarea."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Acasă pentru a anula fixarea."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Pot fi accesate date cu caracter personal (cum ar fi agenda și conținutul e-mailurilor)."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 916b2c7923e7..d2bda6e4e259 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -601,7 +601,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"Приложение закреплено"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Обзор\"."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Главный экран\"."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Экран будет зафиксирован, пока вы не отмените блокировку (для этого нужно провести вверх и удерживать)."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Оно будет показываться на экране, пока вы его не открепите (для этого нужно провести вверх и удерживать)."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопку \"Обзор\"."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопку \"Главный экран\"."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Может быть получен доступ к персональным данным (например, контактам и содержимому электронных писем)."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 684e29645978..c776f2e7a3f0 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -601,10 +601,10 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikácia je pripnutá"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidiel Späť a Prehľad."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho pridržaním tlačidiel Späť a Domov."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Táto možnosť ponechá položku v zobrazení, dokým ju neodopnete. Odpojíte potiahnutím a pridržaním."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Táto možnosť ponechá položku v zobrazení, dokým ju neodopnete. Odpojíte ju potiahnutím nahor a pridržaním."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidla Prehľad."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho pridržaním tlačidla Domov."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Môžu byť prístupné osobné údaje (napríklad kontakty a obsah správ)."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Môže mať prístup k osobným údajom (napríklad kontaktom a obsahu správ)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Pripnutá aplikácia môže otvoriť iné aplikácie."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Túto aplikáciu odopnete pridržaním tlačidiel Späť a Prehľad"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Túto aplikáciu odopnete pridržaním tlačidiel Späť a Domov"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index ab6c93e94fc9..d0d16c367b2c 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -35,7 +35,7 @@
<string name="battery_low_why" msgid="2056750982959359863">"Cilësimet"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Të aktivizohet \"Kursyesi i baterisë\"?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Rreth \"Kursyesit të baterisë\""</string>
- <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ndiz"</string>
+ <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivizo"</string>
<string name="battery_saver_start_action" msgid="4553256017945469937">"Aktivizo \"Kursyesin e baterisë\""</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"Cilësimet"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacioni është i gozhduar"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Kreu\" për ta hequr nga gozhdimi."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Kjo e ruan në pamje deri sa ta zhgozhdosh. Rrëshqit shpejt lart dhe mbaje të shtypur për ta hequr zhgozhduar."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Kjo e ruan në pamje deri sa ta zhgozhdosh. Rrëshqit shpejt lart dhe mbaje të shtypur për ta zhgozhduar."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Kreu\" për ta hequr nga gozhdimi."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Të dhënat personale mund të jenë të qasshme (si kontaktet dhe përmbajtja e email-eve)"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 73eb647303ba..f7d19ac3472d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -599,7 +599,7 @@
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Skärmen visas tills du lossar den. Tryck länge på Översikt om du vill lossa skärmen."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Skärmen visas tills du lossar den. Tryck länge på Startsida om du vill lossa skärmen."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personliga uppgifter kan bli tillgängliga (t.ex. kontakter och innehåll i e-post)."</string>
- <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Det kan gå att öppna andra appar med appen du har fäst."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Den fästa appen kan öppna andra appar."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Om du vill lossa appen trycker du länge på knapparna Tillbaka och Översikt"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Om du vill lossa appen trycker du länge på knapparna Tillbaka och Startsida"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Svep uppåt och håll kvar fingret om du vill lossa appen"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 585228d6411e..ba16febe18c3 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -595,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"ตรึงแอปอยู่"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"กลับ\" และ \"หน้าแรก\" ค้างไว้เพื่อเลิกตรึง"</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"วิธีนี้ช่วยให้เห็นหน้าจอตลอดจนกว่าจะเลิกตรึง เลื่อนขึ้นค้างไว้เพื่อเลิกตรึง"</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"วิธีนี้ช่วยให้เห็นแอปบนหน้าจอตลอดจนกว่าจะเลิกตรึง เลื่อนขึ้นค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"หน้าแรก\" ค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"อาจมีการเข้าถึงข้อมูลส่วนตัว (เช่น รายชื่อติดต่อและเนื้อหาในอีเมล)"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index b163c0c49dfe..e192c120922f 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -609,7 +609,7 @@
<string name="screen_pinning_toast" msgid="8177286912533744328">"Щоб відкріпити цей додаток, натисніть і утримуйте кнопки \"Назад\" та \"Огляд\""</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Щоб відкріпити цей додаток, натисніть і утримуйте кнопки \"Назад\" та \"Головний екран\""</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Щоб відкріпити цей додаток, проведіть пальцем вгору й утримуйте його на екрані"</string>
- <string name="screen_pinning_positive" msgid="3285785989665266984">"Зрозуміло"</string>
+ <string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ні, дякую"</string>
<string name="screen_pinning_start" msgid="7483998671383371313">"Додаток закріплено"</string>
<string name="screen_pinning_exit" msgid="4553787518387346893">"Додаток відкріплено"</string>
@@ -673,7 +673,7 @@
<string name="tuner_warning_title" msgid="7721976098452135267">"Це цікаво, але будьте обачні"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner пропонує нові способи налаштувати та персоналізувати інтерфейс користувача Android. Ці експериментальні функції можуть змінюватися, не працювати чи зникати в майбутніх версіях. Будьте обачні."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"Ці експериментальні функції можуть змінюватися, не працювати чи зникати в майбутніх версіях. Будьте обачні."</string>
- <string name="got_it" msgid="477119182261892069">"Зрозуміло"</string>
+ <string name="got_it" msgid="477119182261892069">"OK"</string>
<string name="tuner_toast" msgid="3812684836514766951">"Вітаємо! System UI Tuner установлено в додатку Налаштування"</string>
<string name="remove_from_settings" msgid="633775561782209994">"Видалити з додатка Налаштування"</string>
<string name="remove_from_settings_prompt" msgid="551565437265615426">"Видалити інструмент System UI Tuner із додатка Налаштування та припинити користуватися всіма його функціями?"</string>
@@ -1018,7 +1018,7 @@
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Нові повідомлення чату з\'являються у вигляді спливаючих значків. Щоб відкрити чат, натисніть його, а щоб перемістити – перетягніть."</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Налаштовуйте спливаючі чати будь-коли"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"Натисніть \"Налаштувати\", щоб вимкнути спливаючі чати від цього додатка"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Зрозуміло"</string>
+ <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
<string name="bubbles_app_settings" msgid="5779443644062348657">"Налаштування параметра \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\""</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацію в системі оновлено. Щоб внести зміни, перейдіть у налаштування."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перейдіть у налаштування, щоб оновити навігацію в системі"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 8246048c51fa..d382f4237c47 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -510,8 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"سبھی کو صاف کریں"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"نظم کریں"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"سرگزشت"</string>
- <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
- <skip />
+ <string name="notification_section_header_incoming" msgid="850925217908095197">"نیا"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"خاموش"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"اطلاعات"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"گفتگوئیں"</string>
@@ -596,7 +595,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"ایپ کو پن کر دیا گیا ہے"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے پیچھے اور مجموعی جائزہ بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"پیچھے\" اور \"ہوم\" بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کے لیے سوائپ کریں اور پکڑ کر رکھیں۔"</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کے لیے اوپر سوائپ کریں اور پکڑ کر رکھیں۔"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے مجموعی جائزہ بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"ہوم\" بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ذاتی ڈیٹا قابل رسائی ہو سکتا ہے (جیسے رابطے اور ای میل کا مواد)۔"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index ab564864c737..cc6a8fd25826 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -593,12 +593,12 @@
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"tắt"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Chuyển đổi thiết bị đầu ra"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Đã ghim ứng dụng"</string>
- <string name="screen_pinning_description" msgid="8699395373875667743">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string>
- <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Quay lại và nút Màn hình chính để bỏ ghim."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Màn hình tiếp tục hiển thị cho tới khi bạn bỏ ghim. Hãy vuốt lên và giữ để bỏ ghim."</string>
- <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Tổng quan để bỏ ghim."</string>
- <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Màn hình chính để bỏ ghim."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dữ liệu cá nhân có thể bị truy cập (chẳng hạn như danh bạ và nội dung email)."</string>
+ <string name="screen_pinning_description" msgid="8699395373875667743">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string>
+ <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Quay lại và nút Màn hình chính để bỏ ghim."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy vuốt lên và giữ để bỏ ghim."</string>
+ <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Tổng quan để bỏ ghim."</string>
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Màn hình chính để bỏ ghim."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Ứng dụng này có thể truy cập dữ liệu cá nhân (chẳng hạn như danh bạ và nội dung email)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Ứng dụng đã ghim có thể mở các ứng dụng khác."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Để bỏ ghim ứng dụng này, hãy chạm và giữ nút Quay lại và nút Tổng quan"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Để bỏ ghim ứng dụng này, hãy chạm và giữ nút Quay lại và nút Màn hình chính"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 84611483e883..9847871c2efc 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -595,11 +595,11 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"應用程式已固定"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住 [返回] 按鈕和主螢幕按鈕即可取消固定。"</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。向上滑動並按住即可取消固定。"</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"這會讓目前的螢幕畫面保持顯示,直到取消固定為止。向上滑動並按住即可取消固定。"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [總覽] 按鈕即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住主螢幕按鈕即可取消固定。"</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"個人資料 (例如聯絡人和電子郵件內容) 可能會遭存取。"</string>
- <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"已設為固定的應用程式或許仍可開啟其他應用程式。"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"已設為固定的應用程式仍可開啟其他應用程式。"</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"如要取消固定這個應用程式,請按住「返回」按鈕和「總覽」按鈕"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"如要取消固定這個應用程式,請按住「返回」按鈕和主畫面按鈕"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"如要取消固定這個應用程式,請向上滑動並按住"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 7f78ddf2cf1c..6da7bc8a2ade 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.bubbles;
-import static android.app.Notification.FLAG_BUBBLE;
import static android.os.AsyncTask.Status.FINISHED;
import static android.view.Display.INVALID_DISPLAY;
@@ -29,21 +28,19 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Path;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.os.Bundle;
+import android.graphics.drawable.Icon;
import android.os.UserHandle;
import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.InstanceId;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -57,17 +54,12 @@ import java.util.Objects;
class Bubble implements BubbleViewProvider {
private static final String TAG = "Bubble";
- /**
- * NotificationEntry associated with the bubble. A null value implies this bubble is loaded
- * from disk.
- */
- @Nullable
- private NotificationEntry mEntry;
private final String mKey;
private long mLastUpdated;
private long mLastAccessed;
+ @Nullable
private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
/** Whether the bubble should show a dot for the notification indicating updated content. */
@@ -75,8 +67,6 @@ class Bubble implements BubbleViewProvider {
/** Whether flyout text should be suppressed, regardless of any other flags or state. */
private boolean mSuppressFlyout;
- /** Whether this bubble should auto expand regardless of the normal flag, used for overflow. */
- private boolean mShouldAutoExpand;
// Items that are typically loaded later
private String mAppName;
@@ -92,6 +82,7 @@ class Bubble implements BubbleViewProvider {
* Presentational info about the flyout.
*/
public static class FlyoutMessage {
+ @Nullable public Icon senderIcon;
@Nullable public Drawable senderAvatar;
@Nullable public CharSequence senderName;
@Nullable public CharSequence message;
@@ -109,16 +100,39 @@ class Bubble implements BubbleViewProvider {
private UserHandle mUser;
@NonNull
private String mPackageName;
+ @Nullable
+ private String mTitle;
+ @Nullable
+ private Icon mIcon;
+ private boolean mIsBubble;
+ private boolean mIsVisuallyInterruptive;
+ private boolean mIsClearable;
+ private boolean mShouldSuppressNotificationDot;
+ private boolean mShouldSuppressNotificationList;
+ private boolean mShouldSuppressPeek;
private int mDesiredHeight;
@DimenRes
private int mDesiredHeightResId;
+ /** for logging **/
+ @Nullable
+ private InstanceId mInstanceId;
+ @Nullable
+ private String mChannelId;
+ private int mNotificationId;
+ private int mAppUid = -1;
+
+ @Nullable
+ private PendingIntent mIntent;
+ @Nullable
+ private PendingIntent mDeleteIntent;
+
/**
* Create a bubble with limited information based on given {@link ShortcutInfo}.
* Note: Currently this is only being used when the bubble is persisted to disk.
*/
Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
- final int desiredHeight, final int desiredHeightResId) {
+ final int desiredHeight, final int desiredHeightResId, @Nullable final String title) {
Objects.requireNonNull(key);
Objects.requireNonNull(shortcutInfo);
mShortcutInfo = shortcutInfo;
@@ -126,8 +140,10 @@ class Bubble implements BubbleViewProvider {
mFlags = 0;
mUser = shortcutInfo.getUserHandle();
mPackageName = shortcutInfo.getPackage();
+ mIcon = shortcutInfo.getIcon();
mDesiredHeight = desiredHeight;
mDesiredHeightResId = desiredHeightResId;
+ mTitle = title;
}
/** Used in tests when no UI is required. */
@@ -145,12 +161,6 @@ class Bubble implements BubbleViewProvider {
return mKey;
}
- @Nullable
- public NotificationEntry getEntry() {
- return mEntry;
- }
-
- @NonNull
public UserHandle getUser() {
return mUser;
}
@@ -203,14 +213,7 @@ class Bubble implements BubbleViewProvider {
@Nullable
public String getTitle() {
- final CharSequence titleCharSeq;
- if (mEntry == null) {
- titleCharSeq = null;
- } else {
- titleCharSeq = mEntry.getSbn().getNotification().extras.getCharSequence(
- Notification.EXTRA_TITLE);
- }
- return titleCharSeq != null ? titleCharSeq.toString() : null;
+ return mTitle;
}
/**
@@ -331,17 +334,44 @@ class Bubble implements BubbleViewProvider {
void setEntry(@NonNull final NotificationEntry entry) {
Objects.requireNonNull(entry);
Objects.requireNonNull(entry.getSbn());
- mEntry = entry;
mLastUpdated = entry.getSbn().getPostTime();
- mFlags = entry.getSbn().getNotification().flags;
+ mIsBubble = entry.getSbn().getNotification().isBubbleNotification();
mPackageName = entry.getSbn().getPackageName();
mUser = entry.getSbn().getUser();
+ mTitle = getTitle(entry);
+ mIsClearable = entry.isClearable();
+ mShouldSuppressNotificationDot = entry.shouldSuppressNotificationDot();
+ mShouldSuppressNotificationList = entry.shouldSuppressNotificationList();
+ mShouldSuppressPeek = entry.shouldSuppressPeek();
+ mChannelId = entry.getSbn().getNotification().getChannelId();
+ mNotificationId = entry.getSbn().getId();
+ mAppUid = entry.getSbn().getUid();
+ mInstanceId = entry.getSbn().getInstanceId();
+ mFlyoutMessage = BubbleViewInfoTask.extractFlyoutMessage(entry);
+ if (entry.getRanking() != null) {
+ mShortcutInfo = entry.getRanking().getShortcutInfo() != null
+ ? entry.getRanking().getShortcutInfo() : mShortcutInfo;
+ mIsVisuallyInterruptive = entry.getRanking().visuallyInterruptive();
+ }
if (entry.getBubbleMetadata() != null) {
+ mFlags = entry.getBubbleMetadata().getFlags();
mDesiredHeight = entry.getBubbleMetadata().getDesiredHeight();
mDesiredHeightResId = entry.getBubbleMetadata().getDesiredHeightResId();
+ mIcon = entry.getBubbleMetadata().getIcon();
+ mIntent = entry.getBubbleMetadata().getIntent();
+ mDeleteIntent = entry.getBubbleMetadata().getDeleteIntent();
}
}
+ @Nullable
+ Icon getIcon() {
+ return mIcon;
+ }
+
+ boolean isVisuallyInterruptive() {
+ return mIsVisuallyInterruptive;
+ }
+
/**
* @return the last time this bubble was updated or accessed, whichever is most recent.
*/
@@ -364,6 +394,19 @@ class Bubble implements BubbleViewProvider {
return mExpandedView != null ? mExpandedView.getVirtualDisplayId() : INVALID_DISPLAY;
}
+ public InstanceId getInstanceId() {
+ return mInstanceId;
+ }
+
+ @Nullable
+ public String getChannelId() {
+ return mChannelId;
+ }
+
+ public int getNotificationId() {
+ return mNotificationId;
+ }
+
/**
* Should be invoked whenever a Bubble is accessed (selected while expanded).
*/
@@ -384,24 +427,19 @@ class Bubble implements BubbleViewProvider {
* Whether this notification should be shown in the shade.
*/
boolean showInShade() {
- if (mEntry == null) return false;
- return !shouldSuppressNotification() || !mEntry.isClearable();
+ return !shouldSuppressNotification() || !mIsClearable;
}
/**
* Sets whether this notification should be suppressed in the shade.
*/
void setSuppressNotification(boolean suppressNotification) {
- if (mEntry == null) return;
boolean prevShowInShade = showInShade();
- Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
- int flags = data.getFlags();
if (suppressNotification) {
- flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ mFlags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
} else {
- flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ mFlags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
}
- data.setFlags(flags);
if (showInShade() != prevShowInShade && mSuppressionListener != null) {
mSuppressionListener.onBubbleNotificationSuppressionChange(this);
@@ -424,9 +462,8 @@ class Bubble implements BubbleViewProvider {
*/
@Override
public boolean showDot() {
- if (mEntry == null) return false;
return mShowBubbleUpdateDot
- && !mEntry.shouldSuppressNotificationDot()
+ && !mShouldSuppressNotificationDot
&& !shouldSuppressNotification();
}
@@ -434,10 +471,9 @@ class Bubble implements BubbleViewProvider {
* Whether the flyout for the bubble should be shown.
*/
boolean showFlyout() {
- if (mEntry == null) return false;
- return !mSuppressFlyout && !mEntry.shouldSuppressPeek()
+ return !mSuppressFlyout && !mShouldSuppressPeek
&& !shouldSuppressNotification()
- && !mEntry.shouldSuppressNotificationList();
+ && !mShouldSuppressNotificationList;
}
/**
@@ -480,25 +516,14 @@ class Bubble implements BubbleViewProvider {
}
}
- /**
- * Whether shortcut information should be used to populate the bubble.
- * <p>
- * To populate the activity use {@link LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)}.
- * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
- */
- boolean usingShortcutInfo() {
- return mEntry != null && mEntry.getBubbleMetadata().getShortcutId() != null
- || mShortcutInfo != null;
+ @Nullable
+ PendingIntent getBubbleIntent() {
+ return mIntent;
}
@Nullable
- PendingIntent getBubbleIntent() {
- if (mEntry == null) return null;
- Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
- if (data != null) {
- return data.getIntent();
- }
- return null;
+ PendingIntent getDeleteIntent() {
+ return mDeleteIntent;
}
Intent getSettingsIntent(final Context context) {
@@ -514,8 +539,12 @@ class Bubble implements BubbleViewProvider {
return intent;
}
+ public int getAppUid() {
+ return mAppUid;
+ }
+
private int getUid(final Context context) {
- if (mEntry != null) return mEntry.getSbn().getUid();
+ if (mAppUid != -1) return mAppUid;
final PackageManager pm = context.getPackageManager();
if (pm == null) return -1;
try {
@@ -548,24 +577,27 @@ class Bubble implements BubbleViewProvider {
}
private boolean shouldSuppressNotification() {
- if (mEntry == null) return true;
- return mEntry.getBubbleMetadata() != null
- && mEntry.getBubbleMetadata().isNotificationSuppressed();
+ return isEnabled(Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
}
- boolean shouldAutoExpand() {
- if (mEntry == null) return mShouldAutoExpand;
- Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata();
- return (metadata != null && metadata.getAutoExpandBubble()) || mShouldAutoExpand;
+ public boolean shouldAutoExpand() {
+ return isEnabled(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
}
void setShouldAutoExpand(boolean shouldAutoExpand) {
- mShouldAutoExpand = shouldAutoExpand;
+ if (shouldAutoExpand) {
+ enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
+ } else {
+ disable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
+ }
+ }
+
+ public void setIsBubble(final boolean isBubble) {
+ mIsBubble = isBubble;
}
public boolean isBubble() {
- if (mEntry == null) return (mFlags & FLAG_BUBBLE) != 0;
- return (mEntry.getSbn().getNotification().flags & FLAG_BUBBLE) != 0;
+ return mIsBubble;
}
public void enable(int option) {
@@ -576,6 +608,10 @@ class Bubble implements BubbleViewProvider {
mFlags &= ~option;
}
+ public boolean isEnabled(int option) {
+ return (mFlags & option) != 0;
+ }
+
@Override
public String toString() {
return "Bubble{" + mKey + '}';
@@ -610,34 +646,24 @@ class Bubble implements BubbleViewProvider {
@Override
public void logUIEvent(int bubbleCount, int action, float normalX, float normalY, int index) {
- if (this.getEntry() == null
- || this.getEntry().getSbn() == null) {
- SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
- null /* package name */,
- null /* notification channel */,
- 0 /* notification ID */,
- 0 /* bubble position */,
- bubbleCount,
- action,
- normalX,
- normalY,
- false /* unread bubble */,
- false /* on-going bubble */,
- false /* isAppForeground (unused) */);
- } else {
- StatusBarNotification notification = this.getEntry().getSbn();
- SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
- notification.getPackageName(),
- notification.getNotification().getChannelId(),
- notification.getId(),
- index,
- bubbleCount,
- action,
- normalX,
- normalY,
- this.showInShade(),
- false /* isOngoing (unused) */,
- false /* isAppForeground (unused) */);
- }
+ SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
+ mPackageName,
+ mChannelId,
+ mNotificationId,
+ index,
+ bubbleCount,
+ action,
+ normalX,
+ normalY,
+ showInShade(),
+ false /* isOngoing (unused) */,
+ false /* isAppForeground (unused) */);
+ }
+
+ @Nullable
+ private static String getTitle(@NonNull final NotificationEntry e) {
+ final CharSequence titleCharSeq = e.getSbn().getNotification().extras.getCharSequence(
+ Notification.EXTRA_TITLE);
+ return titleCharSeq == null ? null : titleCharSeq.toString();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index c4c5da42ec06..b2c5402c7cd3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -505,8 +505,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
addNotifCallback(new NotifCallback() {
@Override
public void removeNotification(NotificationEntry entry, int reason) {
- mNotificationEntryManager.performRemoveNotification(entry.getSbn(),
- reason);
+ mNotificationEntryManager.performRemoveNotification(entry.getSbn(), reason);
}
@Override
@@ -637,8 +636,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mStackView.setExpandListener(mExpandListener);
}
- mStackView.setUnbubbleConversationCallback(notificationEntry ->
- onUserChangedBubble(notificationEntry, false /* shouldBubble */));
+ mStackView.setUnbubbleConversationCallback(key -> {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null) {
+ onUserChangedBubble(entry, false /* shouldBubble */);
+ }
+ });
}
addToWindowManagerMaybe();
@@ -1024,10 +1028,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* @param entry the notification to change bubble state for.
* @param shouldBubble whether the notification should show as a bubble or not.
*/
- public void onUserChangedBubble(@Nullable final NotificationEntry entry, boolean shouldBubble) {
- if (entry == null) {
- return;
- }
+ public void onUserChangedBubble(@NonNull final NotificationEntry entry, boolean shouldBubble) {
NotificationChannel channel = entry.getChannel();
final String appPkg = entry.getSbn().getPackageName();
final int appUid = entry.getSbn().getUid();
@@ -1103,7 +1104,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mBubbleData.removeSuppressedSummary(groupKey);
// Remove any associated bubble children with the summary
- final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
+ final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(
+ groupKey, mNotificationEntryManager);
for (int i = 0; i < bubbleChildren.size(); i++) {
removeBubble(bubbleChildren.get(i).getKey(), DISMISS_GROUP_CANCELLED);
}
@@ -1161,21 +1163,18 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private void setIsBubble(@NonNull final Bubble b, final boolean isBubble) {
Objects.requireNonNull(b);
- if (isBubble) {
- b.enable(FLAG_BUBBLE);
- } else {
- b.disable(FLAG_BUBBLE);
- }
- if (b.getEntry() != null) {
+ b.setIsBubble(isBubble);
+ final NotificationEntry entry = mNotificationEntryManager
+ .getPendingOrActiveNotif(b.getKey());
+ if (entry != null) {
// Updating the entry to be a bubble will trigger our normal update flow
- setIsBubble(b.getEntry(), isBubble, b.shouldAutoExpand());
+ setIsBubble(entry, isBubble, b.shouldAutoExpand());
} else if (isBubble) {
- // If we have no entry to update, it's a persisted bubble so
- // we need to add it to the stack ourselves
+ // If bubble doesn't exist, it's a persisted bubble so we need to add it to the
+ // stack ourselves
Bubble bubble = mBubbleData.getOrCreateBubble(null, b /* persistedBubble */);
inflateAndAdd(bubble, bubble.shouldAutoExpand() /* suppressFlyout */,
!bubble.shouldAutoExpand() /* showInShade */);
-
}
}
@@ -1214,6 +1213,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (reason == DISMISS_NOTIF_CANCEL) {
bubblesToBeRemovedFromRepository.add(bubble);
}
+ final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
+ bubble.getKey());
if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
&& (!bubble.showInShade()
@@ -1222,26 +1223,27 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// The bubble is now gone & the notification is hidden from the shade, so
// time to actually remove it
for (NotifCallback cb : mCallbacks) {
- if (bubble.getEntry() != null) {
- cb.removeNotification(bubble.getEntry(), REASON_CANCEL);
+ if (entry != null) {
+ cb.removeNotification(entry, REASON_CANCEL);
}
}
} else {
if (bubble.isBubble()) {
setIsBubble(bubble, false /* isBubble */);
}
- if (bubble.getEntry() != null && bubble.getEntry().getRow() != null) {
- bubble.getEntry().getRow().updateBubbleButton();
+ if (entry != null && entry.getRow() != null) {
+ entry.getRow().updateBubbleButton();
}
}
}
- if (bubble.getEntry() != null) {
- final String groupKey = bubble.getEntry().getSbn().getGroupKey();
- if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) {
+ if (entry != null) {
+ final String groupKey = entry.getSbn().getGroupKey();
+ if (mBubbleData.getBubblesInGroup(
+ groupKey, mNotificationEntryManager).isEmpty()) {
// Time to potentially remove the summary
for (NotifCallback cb : mCallbacks) {
- cb.maybeCancelSummary(bubble.getEntry());
+ cb.maybeCancelSummary(entry);
}
}
}
@@ -1266,9 +1268,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (update.selectionChanged && mStackView != null) {
mStackView.setSelectedBubble(update.selectedBubble);
- if (update.selectedBubble != null && update.selectedBubble.getEntry() != null) {
- mNotificationGroupManager.updateSuppression(
- update.selectedBubble.getEntry());
+ if (update.selectedBubble != null) {
+ final NotificationEntry entry = mNotificationEntryManager
+ .getPendingOrActiveNotif(update.selectedBubble.getKey());
+ if (entry != null) {
+ mNotificationGroupManager.updateSuppression(entry);
+ }
}
}
@@ -1341,7 +1346,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
String groupKey = entry.getSbn().getGroupKey();
- ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
+ ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(
+ groupKey, mNotificationEntryManager);
boolean isSuppressedSummary = (mBubbleData.isSummarySuppressed(groupKey)
&& mBubbleData.getSummaryKey(groupKey).equals(entry.getKey()));
boolean isSummary = entry.getSbn().getNotification().isGroupSummary();
@@ -1361,9 +1367,15 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// As far as group manager is concerned, once a child is no longer shown
// in the shade, it is essentially removed.
Bubble bubbleChild = mBubbleData.getAnyBubbleWithkey(child.getKey());
- mNotificationGroupManager.onEntryRemoved(bubbleChild.getEntry());
- bubbleChild.setSuppressNotification(true);
- bubbleChild.setShowDot(false /* show */);
+ if (bubbleChild != null) {
+ final NotificationEntry entry = mNotificationEntryManager
+ .getPendingOrActiveNotif(bubbleChild.getKey());
+ if (entry != null) {
+ mNotificationGroupManager.onEntryRemoved(entry);
+ }
+ bubbleChild.setSuppressNotification(true);
+ bubbleChild.setShowDot(false /* show */);
+ }
} else {
// non-bubbled children can be removed
for (NotifCallback cb : mCallbacks) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 20a9a8cf324c..c8706126c1ad 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -22,7 +22,6 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.NonNull;
-import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.util.Log;
@@ -34,6 +33,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController.DismissReason;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.io.FileDescriptor;
@@ -256,8 +256,7 @@ public class BubbleData {
}
mPendingBubbles.remove(bubble.getKey()); // No longer pending once we're here
Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
- suppressFlyout |= bubble.getEntry() == null
- || !bubble.getEntry().getRanking().visuallyInterruptive();
+ suppressFlyout |= !bubble.isVisuallyInterruptive();
if (prevBubble == null) {
// Create a new bubble
@@ -335,13 +334,15 @@ public class BubbleData {
* Retrieves any bubbles that are part of the notification group represented by the provided
* group key.
*/
- ArrayList<Bubble> getBubblesInGroup(@Nullable String groupKey) {
+ ArrayList<Bubble> getBubblesInGroup(@Nullable String groupKey, @NonNull
+ NotificationEntryManager nem) {
ArrayList<Bubble> bubbleChildren = new ArrayList<>();
if (groupKey == null) {
return bubbleChildren;
}
for (Bubble b : mBubbles) {
- if (b.getEntry() != null && groupKey.equals(b.getEntry().getSbn().getGroupKey())) {
+ final NotificationEntry entry = nem.getPendingOrActiveNotif(b.getKey());
+ if (entry != null && groupKey.equals(entry.getSbn().getGroupKey())) {
bubbleChildren.add(b);
}
}
@@ -439,9 +440,7 @@ public class BubbleData {
Bubble newSelected = mBubbles.get(newIndex);
setSelectedBubbleInternal(newSelected);
}
- if (bubbleToRemove.getEntry() != null) {
- maybeSendDeleteIntent(reason, bubbleToRemove.getEntry());
- }
+ maybeSendDeleteIntent(reason, bubbleToRemove);
}
void overflowBubble(@DismissReason int reason, Bubble bubble) {
@@ -611,21 +610,14 @@ public class BubbleData {
return true;
}
- private void maybeSendDeleteIntent(@DismissReason int reason,
- @NonNull final NotificationEntry entry) {
- if (reason == BubbleController.DISMISS_USER_GESTURE) {
- Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata();
- PendingIntent deleteIntent = bubbleMetadata != null
- ? bubbleMetadata.getDeleteIntent()
- : null;
- if (deleteIntent != null) {
- try {
- deleteIntent.send();
- } catch (PendingIntent.CanceledException e) {
- Log.w(TAG, "Failed to send delete intent for bubble with key: "
- + entry.getKey());
- }
- }
+ private void maybeSendDeleteIntent(@DismissReason int reason, @NonNull final Bubble bubble) {
+ if (reason != BubbleController.DISMISS_USER_GESTURE) return;
+ PendingIntent deleteIntent = bubble.getDeleteIntent();
+ if (deleteIntent == null) return;
+ try {
+ deleteIntent.send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "Failed to send delete intent for bubble with key: " + bubble.getKey());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
index d20f40559b5d..0c25d144938c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
@@ -74,11 +74,15 @@ internal class BubbleDataRepository @Inject constructor(
private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> {
return bubbles.mapNotNull { b ->
- var shortcutId = b.shortcutInfo?.id
- if (shortcutId == null) shortcutId = b.entry?.bubbleMetadata?.shortcutId
- if (shortcutId == null) return@mapNotNull null
- BubbleEntity(userId, b.packageName, shortcutId, b.key, b.rawDesiredHeight,
- b.rawDesiredHeightResId)
+ BubbleEntity(
+ userId,
+ b.packageName,
+ b.shortcutInfo?.id ?: return@mapNotNull null,
+ b.key,
+ b.rawDesiredHeight,
+ b.rawDesiredHeightResId,
+ b.title
+ )
}
}
@@ -159,8 +163,13 @@ internal class BubbleDataRepository @Inject constructor(
val bubbles = entities.mapNotNull { entity ->
shortcutMap[ShortcutKey(entity.userId, entity.packageName)]
?.first { shortcutInfo -> entity.shortcutId == shortcutInfo.id }
- ?.let { shortcutInfo -> Bubble(entity.key, shortcutInfo, entity.desiredHeight,
- entity.desiredHeightResId) }
+ ?.let { shortcutInfo -> Bubble(
+ entity.key,
+ shortcutInfo,
+ entity.desiredHeight,
+ entity.desiredHeightResId,
+ entity.title
+ ) }
}
uiScope.launch { cb(bubbles) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index ca359b8efa5d..2f7ffde50fd4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -169,7 +169,7 @@ public class BubbleExpandedView extends LinearLayout {
return;
}
try {
- if (!mIsOverflow && mBubble.usingShortcutInfo()) {
+ if (!mIsOverflow && mBubble.getShortcutInfo() != null) {
options.setApplyActivityFlagsForBubbles(true);
mActivityView.startShortcutActivity(mBubble.getShortcutInfo(),
options, null /* sourceBounds */);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
index 8c76cda3290f..1fa3aaae5e61 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
@@ -31,6 +31,7 @@ import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.text.TextUtils;
import android.view.LayoutInflater;
@@ -223,9 +224,10 @@ public class BubbleFlyoutView extends FrameLayout {
float[] dotCenter,
boolean hideDot) {
- if (flyoutMessage.senderAvatar != null && flyoutMessage.isGroupChat) {
+ final Drawable senderAvatar = flyoutMessage.senderAvatar;
+ if (senderAvatar != null && flyoutMessage.isGroupChat) {
mSenderAvatar.setVisibility(VISIBLE);
- mSenderAvatar.setImageDrawable(flyoutMessage.senderAvatar);
+ mSenderAvatar.setImageDrawable(senderAvatar);
} else {
mSenderAvatar.setVisibility(GONE);
mSenderAvatar.setTranslationX(0);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
index 74231c648f00..a799f2d739e5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
@@ -15,7 +15,8 @@
*/
package com.android.systemui.bubbles;
-import android.app.Notification;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
@@ -50,15 +51,14 @@ public class BubbleIconFactory extends BaseIconFactory {
/**
* Returns the drawable that the developer has provided to display in the bubble.
*/
- Drawable getBubbleDrawable(Context context, ShortcutInfo shortcutInfo,
- Notification.BubbleMetadata metadata) {
+ Drawable getBubbleDrawable(@NonNull final Context context,
+ @Nullable final ShortcutInfo shortcutInfo, @Nullable final Icon ic) {
if (shortcutInfo != null) {
LauncherApps launcherApps =
(LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
int density = context.getResources().getConfiguration().densityDpi;
return launcherApps.getShortcutIconDrawable(shortcutInfo, density);
} else {
- Icon ic = metadata.getIcon();
if (ic != null) {
if (ic.getType() == Icon.TYPE_URI
|| ic.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
index c5faae0d703e..c1dd8c36ff6f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
@@ -16,8 +16,6 @@
package com.android.systemui.bubbles;
-import android.service.notification.StatusBarNotification;
-
import com.android.internal.logging.UiEventLoggerImpl;
/**
@@ -32,12 +30,11 @@ public class BubbleLoggerImpl extends UiEventLoggerImpl implements BubbleLogger
* @param e UI event
*/
public void log(Bubble b, UiEventEnum e) {
- if (b.getEntry() == null) {
+ if (b.getInstanceId() == null) {
// Added from persistence -- TODO log this with specific event?
return;
}
- StatusBarNotification sbn = b.getEntry().getSbn();
- logWithInstanceId(e, sbn.getUid(), sbn.getPackageName(), sbn.getInstanceId());
+ logWithInstanceId(e, b.getAppUid(), b.getPackageName(), b.getInstanceId());
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index b644079be565..0b25c444a8b8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -291,9 +291,7 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V
});
// If the bubble was persisted, the entry is null but it should have shortcut info
- ShortcutInfo info = b.getEntry() == null
- ? b.getShortcutInfo()
- : b.getEntry().getRanking().getShortcutInfo();
+ ShortcutInfo info = b.getShortcutInfo();
if (info == null) {
Log.d(TAG, "ShortcutInfo required to bubble but none found for " + b);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 7cec3d9015d9..0e6ce5cbddb8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -49,6 +49,7 @@ import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
+import android.os.Handler;
import android.provider.Settings;
import android.util.Log;
import android.view.Choreographer;
@@ -91,7 +92,6 @@ import com.android.systemui.bubbles.animation.StackAnimationController;
import com.android.systemui.model.SysUiState;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
import com.android.systemui.util.DismissCircleView;
import com.android.systemui.util.FloatingContentCoordinator;
@@ -160,6 +160,12 @@ public class BubbleStackView extends FrameLayout
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_NO_BOUNCY);
/**
+ * Handler to use for all delayed animations - this way, we can easily cancel them before
+ * starting a new animation.
+ */
+ private final Handler mDelayedAnimationHandler = new Handler();
+
+ /**
* Interface to synchronize {@link View} state and the screen.
*
* {@hide}
@@ -287,12 +293,13 @@ public class BubbleStackView extends FrameLayout
private BubbleController.BubbleExpandListener mExpandListener;
/** Callback to run when we want to unbubble the given notification's conversation. */
- private Consumer<NotificationEntry> mUnbubbleConversationCallback;
+ private Consumer<String> mUnbubbleConversationCallback;
private SysUiState mSysUiState;
private boolean mViewUpdatedRequested = false;
private boolean mIsExpansionAnimating = false;
+ private boolean mIsBubbleSwitchAnimating = false;
private boolean mShowingDismiss = false;
/** The view to desaturate/darken when magneted to the dismiss target. */
@@ -470,6 +477,13 @@ public class BubbleStackView extends FrameLayout
private OnClickListener mBubbleClickListener = new OnClickListener() {
@Override
public void onClick(View view) {
+ // Bubble clicks either trigger expansion/collapse or a bubble switch, both of which we
+ // shouldn't interrupt. These are quick transitions, so it's not worth trying to adjust
+ // the animations inflight.
+ if (mIsExpansionAnimating || mIsBubbleSwitchAnimating) {
+ return;
+ }
+
final Bubble clickedBubble = mBubbleData.getBubbleWithView(view);
// If the bubble has since left us, ignore the click.
@@ -999,10 +1013,7 @@ public class BubbleStackView extends FrameLayout
mManageMenu.findViewById(R.id.bubble_manage_menu_dont_bubble_container).setOnClickListener(
view -> {
showManageMenu(false /* show */);
- final Bubble bubble = mBubbleData.getSelectedBubble();
- if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
- mUnbubbleConversationCallback.accept(bubble.getEntry());
- }
+ mUnbubbleConversationCallback.accept(mBubbleData.getSelectedBubble().getKey());
});
mManageMenu.findViewById(R.id.bubble_manage_menu_settings_container).setOnClickListener(
@@ -1354,7 +1365,7 @@ public class BubbleStackView extends FrameLayout
/** Sets the function to call to un-bubble the given conversation. */
public void setUnbubbleConversationCallback(
- Consumer<NotificationEntry> unbubbleConversationCallback) {
+ Consumer<String> unbubbleConversationCallback) {
mUnbubbleConversationCallback = unbubbleConversationCallback;
}
@@ -1736,6 +1747,8 @@ public class BubbleStackView extends FrameLayout
}
private void animateExpansion() {
+ cancelDelayedExpandCollapseSwitchAnimations();
+
mIsExpanded = true;
hideStackUserEducation(true /* fromExpansion */);
beforeExpandedViewAnimation();
@@ -1784,37 +1797,43 @@ public class BubbleStackView extends FrameLayout
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
}
- postDelayed(() -> PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
- .spring(AnimatableScaleMatrix.SCALE_X,
- AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
- mScaleInSpringConfig)
- .spring(AnimatableScaleMatrix.SCALE_Y,
- AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
- mScaleInSpringConfig)
- .addUpdateListener((target, values) -> {
- if (mExpandedBubble.getIconView() == null) {
- return;
- }
- mExpandedViewContainerMatrix.postTranslate(
- mExpandedBubble.getIconView().getTranslationX()
- - bubbleWillBeAtX,
- 0);
- mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
- })
- .withEndActions(() -> {
- if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
- mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
- }
- })
- .start(), startDelay);
-
+ mDelayedAnimationHandler.postDelayed(() ->
+ PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
+ .spring(AnimatableScaleMatrix.SCALE_X,
+ AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+ mScaleInSpringConfig)
+ .spring(AnimatableScaleMatrix.SCALE_Y,
+ AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+ mScaleInSpringConfig)
+ .addUpdateListener((target, values) -> {
+ if (mExpandedBubble.getIconView() == null) {
+ return;
+ }
+ mExpandedViewContainerMatrix.postTranslate(
+ mExpandedBubble.getIconView().getTranslationX()
+ - bubbleWillBeAtX,
+ 0);
+ mExpandedViewContainer.setAnimationMatrix(
+ mExpandedViewContainerMatrix);
+ })
+ .withEndActions(() -> {
+ if (mExpandedBubble != null
+ && mExpandedBubble.getExpandedView() != null) {
+ mExpandedBubble.getExpandedView()
+ .setSurfaceZOrderedOnTop(false);
+ }
+ })
+ .start(), startDelay);
}
private void animateCollapse() {
+ cancelDelayedExpandCollapseSwitchAnimations();
+
// Hide the menu if it's visible.
showManageMenu(false);
mIsExpanded = false;
+ mIsExpansionAnimating = true;
mBubbleContainer.cancelAllAnimations();
@@ -1834,12 +1853,10 @@ public class BubbleStackView extends FrameLayout
final long startDelay =
(long) (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION * 0.6f);
- postDelayed(() -> mExpandedAnimationController.collapseBackToStack(
+ mDelayedAnimationHandler.postDelayed(() -> mExpandedAnimationController.collapseBackToStack(
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
/* collapseTo */,
- () -> {
- mBubbleContainer.setActiveController(mStackAnimationController);
- }), startDelay);
+ () -> mBubbleContainer.setActiveController(mStackAnimationController)), startDelay);
// We want to visually collapse into this bubble during the animation.
final View expandingFromBubble = mExpandedBubble.getIconView();
@@ -1894,6 +1911,13 @@ public class BubbleStackView extends FrameLayout
}
private void animateSwitchBubbles() {
+ // If we're no longer expanded, this is meaningless.
+ if (!mIsExpanded) {
+ return;
+ }
+
+ mIsBubbleSwitchAnimating = true;
+
// The surface contains a screenshot of the animating out bubble, so we just need to animate
// it out (and then release the GraphicBuffer).
PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
@@ -1919,8 +1943,9 @@ public class BubbleStackView extends FrameLayout
0f, 0f, expandingFromBubbleDestinationX + mBubbleSize / 2f, getExpandedViewY());
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
- mExpandedViewContainer.postDelayed(() -> {
+ mDelayedAnimationHandler.postDelayed(() -> {
if (!mIsExpanded) {
+ mIsBubbleSwitchAnimating = false;
return;
}
@@ -1938,11 +1963,24 @@ public class BubbleStackView extends FrameLayout
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
}
+
+ mIsBubbleSwitchAnimating = false;
})
.start();
}, 25);
}
+ /**
+ * Cancels any delayed steps for expand/collapse and bubble switch animations, and resets the is
+ * animating flags for those animations.
+ */
+ private void cancelDelayedExpandCollapseSwitchAnimations() {
+ mDelayedAnimationHandler.removeCallbacksAndMessages(null);
+
+ mIsExpansionAnimating = false;
+ mIsBubbleSwitchAnimating = false;
+ }
+
private void notifyExpansionChanged(BubbleViewProvider bubble, boolean expanded) {
if (mExpandListener != null && bubble != null) {
mExpandListener.onBubbleExpandChanged(expanded, bubble.getKey());
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
index 525d5b56cc8e..3e4ff5262bbd 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
@@ -37,8 +37,6 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.AsyncTask;
import android.os.Parcelable;
-import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
import android.util.PathParser;
@@ -53,6 +51,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.lang.ref.WeakReference;
import java.util.List;
+import java.util.Objects;
/**
* Simple task to inflate views & load necessary info to display a bubble.
@@ -129,35 +128,10 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
@Nullable
static BubbleViewInfo populate(Context c, BubbleStackView stackView,
BubbleIconFactory iconFactory, Bubble b, boolean skipInflation) {
- final NotificationEntry entry = b.getEntry();
- if (entry == null) {
- // populate from ShortcutInfo when NotificationEntry is not available
- final ShortcutInfo s = b.getShortcutInfo();
- return populate(c, stackView, iconFactory, skipInflation || b.isInflated(),
- s.getPackage(), s.getUserHandle(), s, null);
- }
- final StatusBarNotification sbn = entry.getSbn();
- final String bubbleShortcutId = entry.getBubbleMetadata().getShortcutId();
- final ShortcutInfo si = bubbleShortcutId == null
- ? null : entry.getRanking().getShortcutInfo();
- return populate(
- c, stackView, iconFactory, skipInflation || b.isInflated(),
- sbn.getPackageName(), sbn.getUser(), si, entry);
- }
-
- private static BubbleViewInfo populate(
- @NonNull final Context c,
- @NonNull final BubbleStackView stackView,
- @NonNull final BubbleIconFactory iconFactory,
- final boolean isInflated,
- @NonNull final String packageName,
- @NonNull final UserHandle user,
- @Nullable final ShortcutInfo shortcutInfo,
- @Nullable final NotificationEntry entry) {
BubbleViewInfo info = new BubbleViewInfo();
// View inflation: only should do this once per bubble
- if (!isInflated) {
+ if (!skipInflation && !b.isInflated()) {
LayoutInflater inflater = LayoutInflater.from(c);
info.imageView = (BadgedImageView) inflater.inflate(
R.layout.bubble_view, stackView, false /* attachToRoot */);
@@ -167,8 +141,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
info.expandedView.setStackView(stackView);
}
- if (shortcutInfo != null) {
- info.shortcutInfo = shortcutInfo;
+ if (b.getShortcutInfo() != null) {
+ info.shortcutInfo = b.getShortcutInfo();
}
// App name & app icon
@@ -178,7 +152,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
Drawable appIcon;
try {
appInfo = pm.getApplicationInfo(
- packageName,
+ b.getPackageName(),
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
@@ -186,17 +160,17 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
if (appInfo != null) {
info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
}
- appIcon = pm.getApplicationIcon(packageName);
- badgedIcon = pm.getUserBadgedIcon(appIcon, user);
+ appIcon = pm.getApplicationIcon(b.getPackageName());
+ badgedIcon = pm.getUserBadgedIcon(appIcon, b.getUser());
} catch (PackageManager.NameNotFoundException exception) {
// If we can't find package... don't think we should show the bubble.
- Log.w(TAG, "Unable to find package: " + packageName);
+ Log.w(TAG, "Unable to find package: " + b.getPackageName());
return null;
}
// Badged bubble image
Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
- entry == null ? null : entry.getBubbleMetadata());
+ b.getIcon());
if (bubbleDrawable == null) {
// Default to app icon
bubbleDrawable = appIcon;
@@ -222,8 +196,10 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
Color.WHITE, WHITE_SCRIM_ALPHA);
// Flyout
- if (entry != null) {
- info.flyoutMessage = extractFlyoutMessage(c, entry);
+ info.flyoutMessage = b.getFlyoutMessage();
+ if (info.flyoutMessage != null) {
+ info.flyoutMessage.senderAvatar =
+ loadSenderAvatar(c, info.flyoutMessage.senderIcon);
}
return info;
}
@@ -235,8 +211,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
* notification, based on its type. Returns null if there should not be an update message.
*/
@NonNull
- static Bubble.FlyoutMessage extractFlyoutMessage(Context context,
- NotificationEntry entry) {
+ static Bubble.FlyoutMessage extractFlyoutMessage(NotificationEntry entry) {
+ Objects.requireNonNull(entry);
final Notification underlyingNotif = entry.getSbn().getNotification();
final Class<? extends Notification.Style> style = underlyingNotif.getNotificationStyle();
@@ -264,20 +240,9 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
if (latestMessage != null) {
bubbleMessage.message = latestMessage.getText();
Person sender = latestMessage.getSenderPerson();
- bubbleMessage.senderName = sender != null
- ? sender.getName()
- : null;
-
+ bubbleMessage.senderName = sender != null ? sender.getName() : null;
bubbleMessage.senderAvatar = null;
- if (sender != null && sender.getIcon() != null) {
- if (sender.getIcon().getType() == Icon.TYPE_URI
- || sender.getIcon().getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
- context.grantUriPermission(context.getPackageName(),
- sender.getIcon().getUri(),
- Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- bubbleMessage.senderAvatar = sender.getIcon().loadDrawable(context);
- }
+ bubbleMessage.senderIcon = sender != null ? sender.getIcon() : null;
return bubbleMessage;
}
} else if (Notification.InboxStyle.class.equals(style)) {
@@ -306,4 +271,15 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
return bubbleMessage;
}
+
+ @Nullable
+ static Drawable loadSenderAvatar(@NonNull final Context context, @Nullable final Icon icon) {
+ Objects.requireNonNull(context);
+ if (icon == null) return null;
+ if (icon.getType() == Icon.TYPE_URI || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ context.grantUriPermission(context.getPackageName(),
+ icon.getUri(), Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ return icon.loadDrawable(context);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
index 355c4b115c8d..24768cd84a76 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
@@ -24,5 +24,6 @@ data class BubbleEntity(
val shortcutId: String,
val key: String,
val desiredHeight: Int,
- @DimenRes val desiredHeightResId: Int
+ @DimenRes val desiredHeightResId: Int,
+ val title: String? = null
)
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
index a8faf258da07..66fff3386ae1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
@@ -33,6 +33,7 @@ private const val ATTR_SHORTCUT_ID = "sid"
private const val ATTR_KEY = "key"
private const val ATTR_DESIRED_HEIGHT = "h"
private const val ATTR_DESIRED_HEIGHT_RES_ID = "hid"
+private const val ATTR_TITLE = "t"
/**
* Writes the bubbles in xml format into given output stream.
@@ -63,6 +64,7 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) {
serializer.attribute(null, ATTR_KEY, bubble.key)
serializer.attribute(null, ATTR_DESIRED_HEIGHT, bubble.desiredHeight.toString())
serializer.attribute(null, ATTR_DESIRED_HEIGHT_RES_ID, bubble.desiredHeightResId.toString())
+ bubble.title?.let { serializer.attribute(null, ATTR_TITLE, it) }
serializer.endTag(null, TAG_BUBBLE)
} catch (e: IOException) {
throw RuntimeException(e)
@@ -92,7 +94,8 @@ private fun readXmlEntry(parser: XmlPullParser): BubbleEntity? {
parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null,
parser.getAttributeWithName(ATTR_KEY) ?: return null,
parser.getAttributeWithName(ATTR_DESIRED_HEIGHT)?.toInt() ?: return null,
- parser.getAttributeWithName(ATTR_DESIRED_HEIGHT_RES_ID)?.toInt() ?: return null
+ parser.getAttributeWithName(ATTR_DESIRED_HEIGHT_RES_ID)?.toInt() ?: return null,
+ parser.getAttributeWithName(ATTR_TITLE)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/UserAwareController.kt b/packages/SystemUI/src/com/android/systemui/controls/UserAwareController.kt
index 693c2708b0f7..d2776d27ae62 100644
--- a/packages/SystemUI/src/com/android/systemui/util/UserAwareController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/UserAwareController.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.util
+package com.android.systemui.controls
import android.os.UserHandle
@@ -23,8 +23,6 @@ import android.os.UserHandle
* changes.
*/
interface UserAwareController {
- @JvmDefault
fun changeUser(newUser: UserHandle) {}
-
val currentUserId: Int
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
index eed55315e836..d4d4d2a7d8fe 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
@@ -20,7 +20,7 @@ import android.content.ComponentName
import android.service.controls.Control
import android.service.controls.ControlsProviderService
import android.service.controls.actions.ControlAction
-import com.android.systemui.util.UserAwareController
+import com.android.systemui.controls.UserAwareController
import java.util.function.Consumer
/**
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index 496741b1cd6f..45ba1e6012fe 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -21,7 +21,7 @@ import android.service.controls.Control
import android.service.controls.ControlsProviderService
import android.service.controls.actions.ControlAction
import com.android.systemui.controls.ControlStatus
-import com.android.systemui.util.UserAwareController
+import com.android.systemui.controls.UserAwareController
import com.android.systemui.controls.management.ControlsFavoritingActivity
import com.android.systemui.controls.ui.ControlsUiController
import java.util.function.Consumer
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 26124f7f3285..05433197799e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -238,7 +238,7 @@ internal class ControlHolder(
updateFavorite(!favorite.isChecked)
favoriteCallback(wrapper.controlId, favorite.isChecked)
}
- applyRenderInfo(renderInfo)
+ applyRenderInfo(renderInfo, wrapper.deviceType)
}
override fun updateFavorite(favorite: Boolean) {
@@ -254,12 +254,16 @@ internal class ControlHolder(
return RenderInfo.lookup(itemView.context, component, deviceType)
}
- private fun applyRenderInfo(ri: RenderInfo) {
+ private fun applyRenderInfo(ri: RenderInfo, @DeviceTypes.DeviceType deviceType: Int) {
val context = itemView.context
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
icon.setImageDrawable(ri.icon)
- icon.setImageTintList(fg)
+
+ // Do not color app icons
+ if (deviceType != DeviceTypes.TYPE_ROUTINE) {
+ icon.setImageTintList(fg)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
index b9f16665944f..647daccca8bd 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
@@ -18,7 +18,7 @@ package com.android.systemui.controls.management
import android.content.ComponentName
import com.android.systemui.controls.ControlsServiceInfo
-import com.android.systemui.util.UserAwareController
+import com.android.systemui.controls.UserAwareController
import com.android.systemui.statusbar.policy.CallbackController
/**
@@ -26,7 +26,7 @@ import com.android.systemui.statusbar.policy.CallbackController
*/
interface ControlsListingController :
CallbackController<ControlsListingController.ControlsListingCallback>,
- UserAwareController {
+ UserAwareController {
/**
* @return the current list of services that satisfies the [ServiceListing].
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index ee02b85e4a00..e8530272a5c8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -274,7 +274,6 @@ class ControlViewHolder(
val ri = RenderInfo.lookup(context, cws.componentName, deviceTypeOrError, offset)
val fg = context.resources.getColorStateList(ri.foreground, context.theme)
val newText = nextStatusText
- nextStatusText = ""
val control = cws.control
var shouldAnimate = animated
@@ -297,10 +296,8 @@ class ControlViewHolder(
if (immediately) {
status.alpha = STATUS_ALPHA_ENABLED
status.text = text
- nextStatusText = ""
- } else {
- nextStatusText = text
}
+ nextStatusText = text
}
private fun animateBackgroundChange(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
index 48f945874135..9dd0f534e3a8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
@@ -21,6 +21,7 @@ import android.graphics.drawable.LayerDrawable
import android.view.View
import android.service.controls.Control
import android.service.controls.templates.ControlTemplate
+import android.service.controls.templates.StatelessTemplate
import com.android.systemui.R
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL
@@ -35,24 +36,44 @@ class TouchBehavior : Behavior {
lateinit var template: ControlTemplate
lateinit var control: Control
lateinit var cvh: ControlViewHolder
+ private var statelessTouch = false
+ private var lastColorOffset = 0
+ private val enabled: Boolean
+ get() = if (lastColorOffset > 0 || statelessTouch) true else false
+
+ companion object {
+ const val STATELESS_ENABLE_TIMEOUT_IN_MILLIS = 3000L
+ }
override fun initialize(cvh: ControlViewHolder) {
this.cvh = cvh
cvh.layout.setOnClickListener(View.OnClickListener() {
cvh.controlActionCoordinator.touch(cvh, template.getTemplateId(), control)
+
+ // StatelessTemplates have no state, with no way to discern between enabled and
+ // disabled. Render an enabled state for a few moments to let the user know the
+ // action is in progress.
+ if (template is StatelessTemplate) {
+ statelessTouch = true
+ cvh.applyRenderInfo(enabled, lastColorOffset)
+ cvh.uiExecutor.executeDelayed({
+ statelessTouch = false
+ cvh.applyRenderInfo(enabled, lastColorOffset)
+ }, STATELESS_ENABLE_TIMEOUT_IN_MILLIS)
+ }
})
}
override fun bind(cws: ControlWithState, colorOffset: Int) {
this.control = cws.control!!
+ lastColorOffset = colorOffset
cvh.setStatusText(control.getStatusText())
template = control.getControlTemplate()
val ld = cvh.layout.getBackground() as LayerDrawable
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
- val enabled = if (colorOffset > 0) true else false
clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
cvh.applyRenderInfo(enabled, colorOffset)
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index a2086e8d3ac6..16f76deca6c6 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -68,7 +68,7 @@ public class LogModule {
public static LogBuffer provideNotificationSectionLogBuffer(
LogcatEchoTracker bufferFilter,
DumpManager dumpManager) {
- LogBuffer buffer = new LogBuffer("NotifSectionLog", 500, 10, bufferFilter);
+ LogBuffer buffer = new LogBuffer("NotifSectionLog", 1000, 10, bufferFilter);
buffer.attach(dumpManager);
return buffer;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 50081001e65a..d5a28378c993 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -257,16 +257,18 @@ public class MediaControlPanel {
rect.setColor(Color.TRANSPARENT);
final MediaDeviceData device = data.getDevice();
+ int seamlessId = mViewHolder.getSeamless().getId();
if (device != null && !device.getEnabled()) {
mViewHolder.getSeamless().setEnabled(false);
- // TODO(b/156875717): setEnabled should cause the alpha to change.
- mViewHolder.getSeamless().setAlpha(0.38f);
+ expandedSet.setAlpha(seamlessId, 0.38f);
+ collapsedSet.setAlpha(seamlessId, 0.38f);
iconView.setImageResource(R.drawable.ic_hardware_speaker);
iconView.setVisibility(View.VISIBLE);
deviceName.setText(R.string.media_seamless_remote_device);
} else if (device != null) {
mViewHolder.getSeamless().setEnabled(true);
- mViewHolder.getSeamless().setAlpha(1f);
+ expandedSet.setAlpha(seamlessId, 1.0f);
+ collapsedSet.setAlpha(seamlessId, 1.0f);
Drawable icon = device.getIcon();
iconView.setVisibility(View.VISIBLE);
@@ -282,7 +284,8 @@ public class MediaControlPanel {
// Reset to default
Log.w(TAG, "device is null. Not binding output chip.");
mViewHolder.getSeamless().setEnabled(true);
- mViewHolder.getSeamless().setAlpha(1f);
+ expandedSet.setAlpha(seamlessId, 1.0f);
+ collapsedSet.setAlpha(seamlessId, 1.0f);
iconView.setVisibility(View.GONE);
deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index d077666f8184..856c19290af6 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -491,10 +491,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
Log.d(TAG, "resizeAndAnimatePipUnchecked: toBounds=" + toBounds
+ " duration=" + duration + " callers=\n" + Debug.getCallers(5, " "));
}
- if (!toBounds.equals(mBounds)) {
- mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, mUpdateBoundsCallback);
- setAnimatingToBounds(toBounds);
- }
+
+ // Intentionally resize here even if the current bounds match the destination bounds.
+ // This is so all the proper callbacks are performed.
+ mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, mUpdateBoundsCallback);
+ setAnimatingToBounds(toBounds);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index f6b212c6f19f..c151715cd4ef 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -260,12 +260,14 @@ public class PipResizeGestureHandler {
private void onMotionEvent(MotionEvent ev) {
int action = ev.getActionMasked();
+ float x = ev.getX();
+ float y = ev.getY();
if (action == MotionEvent.ACTION_DOWN) {
mLastResizeBounds.setEmpty();
- mAllowGesture = isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
+ mAllowGesture = isWithinTouchRegion((int) x, (int) y);
if (mAllowGesture) {
- setCtrlType((int) ev.getX(), (int) ev.getY());
- mDownPoint.set(ev.getX(), ev.getY());
+ setCtrlType((int) x, (int) y);
+ mDownPoint.set(x, y);
mLastDownBounds.set(mMotionHelper.getBounds());
}
@@ -277,20 +279,23 @@ public class PipResizeGestureHandler {
break;
case MotionEvent.ACTION_MOVE:
// Capture inputs
- float dx = Math.abs(ev.getX() - mDownPoint.x);
- float dy = Math.abs(ev.getY() - mDownPoint.y);
- if (!mThresholdCrossed && dx > mTouchSlop && dy > mTouchSlop) {
+ if (!mThresholdCrossed
+ && Math.hypot(x - mDownPoint.x, y - mDownPoint.y) > mTouchSlop) {
mThresholdCrossed = true;
+ // Reset the down to begin resizing from this point
+ mDownPoint.set(x, y);
mInputMonitor.pilferPointers();
}
- final Rect currentPipBounds = mMotionHelper.getBounds();
- mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(),
- mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
- mMinSize.y, mMaxSize, true,
- mLastDownBounds.width() > mLastDownBounds.height()));
- mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
- mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds,
- null);
+ if (mThresholdCrossed) {
+ final Rect currentPipBounds = mMotionHelper.getBounds();
+ mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(x, y,
+ mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
+ mMinSize.y, mMaxSize, true,
+ mLastDownBounds.width() > mLastDownBounds.height()));
+ mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
+ mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds,
+ null);
+ }
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
index 0a84f5ee1bb9..2365e67fec2f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
@@ -23,7 +23,6 @@ import static com.android.systemui.statusbar.phone.AutoTileManager.WORK;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
-import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -31,7 +30,6 @@ import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
-import com.android.systemui.util.UserAwareController;
import java.util.Arrays;
import java.util.Collection;
@@ -39,7 +37,7 @@ import java.util.Collections;
import javax.inject.Inject;
-public class AutoAddTracker implements UserAwareController {
+public class AutoAddTracker {
private static final String[][] CONVERT_PREFS = {
{Key.QS_HOTSPOT_ADDED, HOTSPOT},
@@ -51,39 +49,20 @@ public class AutoAddTracker implements UserAwareController {
private final ArraySet<String> mAutoAdded;
private final Context mContext;
- private int mUserId;
- public AutoAddTracker(Context context, int userId) {
+ @Inject
+ public AutoAddTracker(Context context) {
mContext = context;
- mUserId = userId;
mAutoAdded = new ArraySet<>(getAdded());
// TODO: remove migration code and shared preferences keys after P release
- if (mUserId == UserHandle.USER_SYSTEM) {
- for (String[] convertPref : CONVERT_PREFS) {
- if (Prefs.getBoolean(context, convertPref[0], false)) {
- setTileAdded(convertPref[1]);
- Prefs.remove(context, convertPref[0]);
- }
+ for (String[] convertPref : CONVERT_PREFS) {
+ if (Prefs.getBoolean(context, convertPref[0], false)) {
+ setTileAdded(convertPref[1]);
+ Prefs.remove(context, convertPref[0]);
}
}
mContext.getContentResolver().registerContentObserver(
- Secure.getUriFor(Secure.QS_AUTO_ADDED_TILES), false, mObserver,
- UserHandle.USER_ALL);
- }
-
- @Override
- public void changeUser(UserHandle newUser) {
- if (newUser.getIdentifier() == mUserId) {
- return;
- }
- mUserId = newUser.getIdentifier();
- mAutoAdded.clear();
- mAutoAdded.addAll(getAdded());
- }
-
- @Override
- public int getCurrentUserId() {
- return mUserId;
+ Secure.getUriFor(Secure.QS_AUTO_ADDED_TILES), false, mObserver);
}
public boolean isAdded(String tile) {
@@ -107,13 +86,12 @@ public class AutoAddTracker implements UserAwareController {
}
private void saveTiles() {
- Secure.putStringForUser(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES,
- TextUtils.join(",", mAutoAdded), mUserId);
+ Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES,
+ TextUtils.join(",", mAutoAdded));
}
private Collection<String> getAdded() {
- String current = Secure.getStringForUser(mContext.getContentResolver(),
- Secure.QS_AUTO_ADDED_TILES, mUserId);
+ String current = Secure.getString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES);
if (current == null) {
return Collections.emptyList();
}
@@ -124,27 +102,7 @@ public class AutoAddTracker implements UserAwareController {
protected final ContentObserver mObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
- mAutoAdded.clear();
mAutoAdded.addAll(getAdded());
}
};
-
- public static class Builder {
- private final Context mContext;
- private int mUserId;
-
- @Inject
- public Builder(Context context) {
- mContext = context;
- }
-
- public Builder setUserId(int userId) {
- mUserId = userId;
- return this;
- }
-
- public AutoAddTracker build() {
- return new AutoAddTracker(mContext, mUserId);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 28369925367a..3eed8ad89075 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -291,15 +291,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
}
private void emptyAndInflateOrRemovePages() {
- final int nTiles = mTiles.size();
- // We should always have at least one page, even if it's empty.
- int numPages = Math.max(nTiles / mPages.get(0).maxTiles(), 1);
-
- // Add one more not full page if needed
- if (nTiles > numPages * mPages.get(0).maxTiles()) {
- numPages++;
- }
-
+ final int numPages = getNumPages();
final int NP = mPages.size();
for (int i = 0; i < NP; i++) {
mPages.get(i).removeAllViews();
@@ -431,6 +423,22 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
return mPages.get(0).mColumns;
}
+ /**
+ * Gets the number of pages in this paged tile layout
+ */
+ public int getNumPages() {
+ final int nTiles = mTiles.size();
+ // We should always have at least one page, even if it's empty.
+ int numPages = Math.max(nTiles / mPages.get(0).maxTiles(), 1);
+
+ // Add one more not full page if needed
+ if (nTiles > numPages * mPages.get(0).maxTiles()) {
+ numPages++;
+ }
+
+ return numPages;
+ }
+
public int getNumVisibleTiles() {
if (mPages.size() == 0) return 0;
TilePage currentPage = mPages.get(getCurrentPageNumber());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index fc8e36ff22cf..c4bb4e86e41e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -218,7 +218,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
.addFloat(mActionsContainer, "alpha", 0, 1)
.addFloat(mEditContainer, "alpha", 0, 1)
.addFloat(mPageIndicator, "alpha", 0, 1)
- .setStartDelay(0.15f)
+ .setStartDelay(0.9f)
.build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index ecdb2c91ca48..0fc3829fab66 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -240,8 +240,13 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
if (mTileLayout instanceof PagedTileLayout) {
+ // Since PageIndicator gets measured before PagedTileLayout, we preemptively set the
+ // # of pages before the measurement pass so PageIndicator is measured appropriately
+ if (mFooterPageIndicator != null) {
+ mFooterPageIndicator.setNumPages(((PagedTileLayout) mTileLayout).getNumPages());
+ }
+
// Allow the UI to be as big as it want's to, we're in a scroll view
int newHeight = 10000;
int availableHeight = MeasureSpec.getSize(heightMeasureSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 858a7e2e30e0..65d3572d04a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -255,9 +255,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
int currentUser = ActivityManager.getCurrentUser();
if (currentUser != mCurrentUser) {
mUserContext = mContext.createContextAsUser(UserHandle.of(currentUser), 0);
- if (mAutoTiles != null) {
- mAutoTiles.changeUser(UserHandle.of(currentUser));
- }
}
if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return;
mTiles.entrySet().stream().filter(tile -> !tileSpecs.contains(tile.getKey())).forEach(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 311eda2f4ad8..b5afe771926c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -15,6 +15,7 @@
package com.android.systemui.qs;
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
@@ -41,6 +42,7 @@ import android.util.Pair;
import android.view.ContextThemeWrapper;
import android.view.DisplayCutout;
import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.ImageView;
import android.widget.RelativeLayout;
@@ -347,6 +349,15 @@ public class QuickStatusBarHeader extends RelativeLayout implements
com.android.internal.R.dimen.quick_qs_offset_height);
mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
+ ViewGroup.LayoutParams lp = getLayoutParams();
+ if (mQsDisabled) {
+ lp.height = resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.quick_qs_offset_height);
+ } else {
+ lp.height = WRAP_CONTENT;
+ }
+ setLayoutParams(lp);
+
updateStatusIconAlphaAnimator();
updateHeaderTextContainerAlphaAnimator();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index f3e2f104621e..f89185e3efa9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -118,6 +118,7 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
try {
if (mOverviewProxyService.getProxy() != null) {
mOverviewProxyService.getProxy().onOverviewToggle();
+ mOverviewProxyService.notifyToggleRecentApps();
}
} catch (RemoteException e) {
Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 8a012b8b06f1..790b2585190d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -200,11 +200,13 @@ public class OverviewProxyService extends CurrentUserTracker implements
mInputFocusTransferStartY = event.getY();
mInputFocusTransferStartMillis = event.getEventTime();
statusBar.onInputFocusTransfer(
- mInputFocusTransferStarted, 0 /* velocity */);
+ mInputFocusTransferStarted, false /* cancel */,
+ 0 /* velocity */);
}
if (action == ACTION_UP || action == ACTION_CANCEL) {
mInputFocusTransferStarted = false;
statusBar.onInputFocusTransfer(mInputFocusTransferStarted,
+ action == ACTION_CANCEL,
(event.getY() - mInputFocusTransferStartY)
/ (event.getEventTime() - mInputFocusTransferStartMillis));
}
@@ -692,7 +694,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
mHandler.post(()-> {
mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {
mInputFocusTransferStarted = false;
- statusBarLazy.get().onInputFocusTransfer(false, 0 /* velocity */);
+ statusBarLazy.get().onInputFocusTransfer(false, true /* cancel */,
+ 0 /* velocity */);
});
});
}
@@ -871,6 +874,12 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
}
+ void notifyToggleRecentApps() {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onToggleRecentApps();
+ }
+ }
+
private void updateEnabledState() {
mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent,
MATCH_SYSTEM_ONLY,
@@ -901,6 +910,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
default void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {}
default void onOverviewShown(boolean fromHome) {}
default void onQuickScrubStarted() {}
+ /** Notify the recents app (overview) is started by 3-button navigation. */
+ default void onToggleRecentApps() {}
/** Notify changes in the nav bar button alpha */
default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {}
default void onSystemUiStateChanged(int sysuiStateFlags) {}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 7babe2f4f2db..ca3753286bf9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -215,7 +215,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
private Animator mScreenshotAnimation;
private Runnable mOnCompleteRunnable;
private Animator mDismissAnimation;
- private SavedImageData mImageData;
private boolean mInDarkMode = false;
private boolean mDirectionLTR = true;
private boolean mOrientationPortrait = true;
@@ -234,9 +233,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
switch (msg.what) {
case MESSAGE_CORNER_TIMEOUT:
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT);
- if (mImageData != null) {
- mNotificationsController.showSilentScreenshotNotification(mImageData);
- }
GlobalScreenshot.this.dismissScreenshot("timeout", false);
mOnCompleteRunnable.run();
break;
@@ -408,9 +404,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
mDismissButton = mScreenshotLayout.findViewById(R.id.global_screenshot_dismiss_button);
mDismissButton.setOnClickListener(view -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL);
- if (mImageData != null) {
- mNotificationsController.showSilentScreenshotNotification(mImageData);
- }
dismissScreenshot("dismiss_button", false);
mOnCompleteRunnable.run();
});
@@ -450,10 +443,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
});
}
- mImageData = null; // make sure we clear the current stored data
- mNotificationsController.reset();
- mNotificationsController.setImage(mScreenBitmap);
-
mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data);
mSaveInBgTask.execute();
}
@@ -670,7 +659,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
*/
private void showUiOnActionsReady(SavedImageData imageData) {
logSuccessOnActionsReady(imageData);
- mImageData = imageData;
AccessibilityManager accessibilityManager = (AccessibilityManager)
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
index e4e253e71fb3..fbcd6ba0ff47 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
@@ -148,11 +148,43 @@ public class ScreenshotNotificationsController {
}
/**
- * Shows a silent notification with the saved screenshot and actions that can be taken with it.
+ * Shows a notification to inform the user that a screenshot is currently being saved.
+ */
+ public void showSavingScreenshotNotification() {
+ final long now = System.currentTimeMillis();
+
+ mPublicNotificationBuilder
+ .setContentTitle(mResources.getString(R.string.screenshot_saving_title))
+ .setSmallIcon(R.drawable.stat_notify_image)
+ .setCategory(Notification.CATEGORY_PROGRESS)
+ .setWhen(now)
+ .setShowWhen(true)
+ .setColor(mResources.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
+ SystemUI.overrideNotificationAppName(mContext, mPublicNotificationBuilder, true);
+
+ mNotificationBuilder
+ .setContentTitle(mResources.getString(R.string.screenshot_saving_title))
+ .setSmallIcon(R.drawable.stat_notify_image)
+ .setWhen(now)
+ .setShowWhen(true)
+ .setColor(mResources.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setStyle(mNotificationStyle)
+ .setPublicVersion(mPublicNotificationBuilder.build());
+ mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true);
+ SystemUI.overrideNotificationAppName(mContext, mNotificationBuilder, true);
+
+ mNotificationManager.notify(SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT,
+ mNotificationBuilder.build());
+ }
+
+ /**
+ * Shows a notification with the saved screenshot and actions that can be taken with it.
*
* @param actionData SavedImageData struct with image URI and actions
*/
- public void showSilentScreenshotNotification(
+ public void showScreenshotActionsNotification(
GlobalScreenshot.SavedImageData actionData) {
mNotificationBuilder.addAction(actionData.shareAction);
mNotificationBuilder.addAction(actionData.editAction);
@@ -174,34 +206,20 @@ public class ScreenshotNotificationsController {
.setContentTitle(mResources.getString(R.string.screenshot_saved_title))
.setContentText(mResources.getString(R.string.screenshot_saved_text))
.setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0))
- .setSmallIcon(R.drawable.stat_notify_image)
- .setCategory(Notification.CATEGORY_PROGRESS)
.setWhen(now)
- .setShowWhen(true)
.setAutoCancel(true)
.setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setGroup("silent")
- .setGroupAlertBehavior(Notification.GROUP_ALERT_SUMMARY);
+ com.android.internal.R.color.system_notification_accent_color));
mNotificationBuilder
.setContentTitle(mResources.getString(R.string.screenshot_saved_title))
.setContentText(mResources.getString(R.string.screenshot_saved_text))
.setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0))
- .setSmallIcon(R.drawable.stat_notify_image)
- .setCategory(Notification.CATEGORY_PROGRESS)
.setWhen(now)
- .setShowWhen(true)
.setAutoCancel(true)
.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setPublicVersion(mPublicNotificationBuilder.build())
- .setStyle(mNotificationStyle)
- .setFlag(Notification.FLAG_NO_CLEAR, false)
- .setGroup("silent")
- .setGroupAlertBehavior(Notification.GROUP_ALERT_SUMMARY);
-
- SystemUI.overrideNotificationAppName(mContext, mPublicNotificationBuilder, true);
- SystemUI.overrideNotificationAppName(mContext, mNotificationBuilder, true);
+ .setFlag(Notification.FLAG_NO_CLEAR, false);
mNotificationManager.notify(SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT,
mNotificationBuilder.build());
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 166934599aeb..21810c0e7cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -253,9 +253,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
mRotateSplitLayout = null;
}
- if (isSplitActive()) {
- update(newConfig);
- }
+ update(newConfig);
}
Handler getHandler() {
@@ -330,6 +328,11 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
mHandler.post(this::removeDivider);
}
+ void onTasksReady() {
+ mHandler.post(() -> update(mDisplayController.getDisplayContext(
+ mContext.getDisplayId()).getResources().getConfiguration()));
+ }
+
private void updateVisibility(final boolean visible) {
if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
if (mVisible != visible) {
@@ -521,7 +524,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
void ensureMinimizedSplit() {
setHomeMinimized(true /* minimized */, mSplits.mSecondary.isResizable());
- if (mView != null && !isDividerVisible()) {
+ if (!isDividerVisible()) {
// Wasn't in split-mode yet, so enter now.
if (DEBUG) {
Slog.d(TAG, " entering split mode with minimized=true");
@@ -532,7 +535,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
void ensureNormalSplit() {
setHomeMinimized(false /* minimized */, mHomeStackResizable);
- if (mView != null && !isDividerVisible()) {
+ if (!isDividerVisible()) {
// Wasn't in split-mode, so enter now.
if (DEBUG) {
Slog.d(TAG, " enter split mode unminimized ");
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 44674df3b865..db324822994b 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -113,6 +113,8 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
t.setColor(mSecondaryDim, new float[]{0f, 0f, 0f});
t.apply();
releaseTransaction(t);
+
+ mDivider.onTasksReady();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
index 08be4f872415..011ad19b41db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
@@ -255,23 +255,11 @@ class IconManager @Inject constructor(
@Throws(InflationException::class)
private fun createPeopleAvatar(entry: NotificationEntry): Icon? {
- // Attempt to extract form shortcut.
- val conversationId = entry.ranking.channel.conversationId
- val query = LauncherApps.ShortcutQuery()
- .setPackage(entry.sbn.packageName)
- .setQueryFlags(
- LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC
- or LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED)
- .setShortcutIds(listOf(conversationId))
- val shortcuts = launcherApps.getShortcuts(query, entry.sbn.user)
var ic: Icon? = null
- if (shortcuts != null && shortcuts.isNotEmpty()) {
- ic = shortcuts[0].icon
- }
- // Fall back to notification large icon if available
- if (ic == null) {
- ic = entry.sbn.notification.getLargeIcon()
+ val shortcut = entry.ranking.shortcutInfo
+ if (shortcut != null) {
+ ic = launcherApps.getShortcutIcon(shortcut)
}
// Fall back to extract from message
@@ -290,6 +278,11 @@ class IconManager @Inject constructor(
}
}
+ // Fall back to notification large icon if available
+ if (ic == null) {
+ ic = entry.sbn.notification.getLargeIcon()
+ }
+
// Revert to small icon if still not available
if (ic == null) {
ic = entry.sbn.notification.smallIcon
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index ad047889f29f..bd0d0b31e4dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -29,6 +29,7 @@ import android.util.Log;
import androidx.annotation.Nullable;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
@@ -36,6 +37,7 @@ import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -58,6 +60,7 @@ import javax.inject.Inject;
*/
public class NotificationLogger implements StateListener {
private static final String TAG = "NotificationLogger";
+ private static final boolean DEBUG = false;
/** The minimum delay in ms between reports of notification visibility. */
private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500;
@@ -79,7 +82,12 @@ public class NotificationLogger implements StateListener {
private long mLastVisibilityReportUptimeMs;
private NotificationListContainer mListContainer;
private final Object mDozingLock = new Object();
- private boolean mDozing;
+ @GuardedBy("mDozingLock")
+ private Boolean mDozing = null; // Use null to indicate state is not yet known
+ @GuardedBy("mDozingLock")
+ private Boolean mLockscreen = null; // Use null to indicate state is not yet known
+ private Boolean mPanelExpanded = null; // Use null to indicate state is not yet known
+ private boolean mLogging = false;
protected final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
new OnChildLocationsChangedListener() {
@@ -247,33 +255,44 @@ public class NotificationLogger implements StateListener {
}
public void stopNotificationLogging() {
- // Report all notifications as invisible and turn down the
- // reporter.
- if (!mCurrentlyVisibleNotifications.isEmpty()) {
- logNotificationVisibilityChanges(
- Collections.emptyList(), mCurrentlyVisibleNotifications);
- recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
+ if (mLogging) {
+ mLogging = false;
+ if (DEBUG) {
+ Log.i(TAG, "stopNotificationLogging: log notifications invisible");
+ }
+ // Report all notifications as invisible and turn down the
+ // reporter.
+ if (!mCurrentlyVisibleNotifications.isEmpty()) {
+ logNotificationVisibilityChanges(
+ Collections.emptyList(), mCurrentlyVisibleNotifications);
+ recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
+ }
+ mHandler.removeCallbacks(mVisibilityReporter);
+ mListContainer.setChildLocationsChangedListener(null);
}
- mHandler.removeCallbacks(mVisibilityReporter);
- mListContainer.setChildLocationsChangedListener(null);
}
public void startNotificationLogging() {
- mListContainer.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
- // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
- // cause the scroller to emit child location events. Hence generate
- // one ourselves to guarantee that we're reporting visible
- // notifications.
- // (Note that in cases where the scroller does emit events, this
- // additional event doesn't break anything.)
- mNotificationLocationsChangedListener.onChildLocationsChanged();
- mNotificationPanelLogger.logPanelShown(mListContainer.hasPulsingNotifications(),
- mEntryManager.getVisibleNotifications());
+ if (!mLogging) {
+ mLogging = true;
+ if (DEBUG) {
+ Log.i(TAG, "startNotificationLogging");
+ }
+ mListContainer.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
+ // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
+ // cause the scroller to emit child location events. Hence generate
+ // one ourselves to guarantee that we're reporting visible
+ // notifications.
+ // (Note that in cases where the scroller does emit events, this
+ // additional event doesn't break anything.)
+ mNotificationLocationsChangedListener.onChildLocationsChanged();
+ }
}
private void setDozing(boolean dozing) {
synchronized (mDozingLock) {
mDozing = dozing;
+ maybeUpdateLoggingStatus();
}
}
@@ -343,19 +362,12 @@ public class NotificationLogger implements StateListener {
for (int i = 0; i < N; i++) {
newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
}
-
- synchronized (mDozingLock) {
- // setNotificationsShown should only be called if we are confident that
- // the user has seen the notification, aka not when ambient display is on
- if (!mDozing) {
- // TODO: Call NotificationEntryManager to do this, once it exists.
- // TODO: Consider not catching all runtime exceptions here.
- try {
- mNotificationListener.setNotificationsShown(newlyVisibleKeyAr);
- } catch (RuntimeException e) {
- Log.d(TAG, "failed setNotificationsShown: ", e);
- }
- }
+ // TODO: Call NotificationEntryManager to do this, once it exists.
+ // TODO: Consider not catching all runtime exceptions here.
+ try {
+ mNotificationListener.setNotificationsShown(newlyVisibleKeyAr);
+ } catch (RuntimeException e) {
+ Log.d(TAG, "failed setNotificationsShown: ", e);
}
}
recycleAllVisibilityObjects(newlyVisibleAr);
@@ -400,14 +412,64 @@ public class NotificationLogger implements StateListener {
@Override
public void onStateChanged(int newState) {
- // don't care about state change
+ if (DEBUG) {
+ Log.i(TAG, "onStateChanged: new=" + newState);
+ }
+ synchronized (mDozingLock) {
+ mLockscreen = (newState == StatusBarState.KEYGUARD
+ || newState == StatusBarState.SHADE_LOCKED);
+ }
}
@Override
public void onDozingChanged(boolean isDozing) {
+ if (DEBUG) {
+ Log.i(TAG, "onDozingChanged: new=" + isDozing);
+ }
setDozing(isDozing);
}
+ @GuardedBy("mDozingLock")
+ private void maybeUpdateLoggingStatus() {
+ if (mPanelExpanded == null || mDozing == null) {
+ if (DEBUG) {
+ Log.i(TAG, "Panel status unclear: panelExpandedKnown="
+ + (mPanelExpanded == null) + " dozingKnown=" + (mDozing == null));
+ }
+ return;
+ }
+ // Once we know panelExpanded and Dozing, turn logging on & off when appropriate
+ boolean lockscreen = mLockscreen == null ? false : mLockscreen;
+ if (mPanelExpanded && !mDozing) {
+ mNotificationPanelLogger.logPanelShown(lockscreen,
+ mEntryManager.getVisibleNotifications());
+ if (DEBUG) {
+ Log.i(TAG, "Notification panel shown, lockscreen=" + lockscreen);
+ }
+ startNotificationLogging();
+ } else {
+ if (DEBUG) {
+ Log.i(TAG, "Notification panel hidden, lockscreen=" + lockscreen);
+ }
+ stopNotificationLogging();
+ }
+ }
+
+ /**
+ * Called by StatusBar to notify the logger that the panel expansion has changed.
+ * The panel may be showing any of the normal notification panel, the AOD, or the bouncer.
+ * @param isExpanded True if the panel is expanded.
+ */
+ public void onPanelExpandedChanged(boolean isExpanded) {
+ if (DEBUG) {
+ Log.i(TAG, "onPanelExpandedChanged: new=" + isExpanded);
+ }
+ mPanelExpanded = isExpanded;
+ synchronized (mDozingLock) {
+ maybeUpdateLoggingStatus();
+ }
+ }
+
/**
* Called when the notification is expanded / collapsed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 0bdac39f35e9..c87b9986ca55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -41,6 +41,7 @@ import com.android.systemui.statusbar.notification.row.StackScrollerDecorView
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.children
+import com.android.systemui.util.takeUntil
import com.android.systemui.util.foldToSparseArray
import javax.inject.Inject
@@ -197,7 +198,7 @@ class NotificationSectionsManager @Inject internal constructor(
else -> null
}
- private fun logShadeContents() = parent.children.forEachIndexed { i, child ->
+ private fun logShadeChild(i: Int, child: View) {
when {
child === incomingHeaderView -> logger.logIncomingHeader(i)
child === mediaControlsView -> logger.logMediaControls(i)
@@ -216,6 +217,7 @@ class NotificationSectionsManager @Inject internal constructor(
}
}
}
+ private fun logShadeContents() = parent.children.forEachIndexed(::logShadeChild)
private val isUsingMultipleSections: Boolean
get() = sectionsFeatureManager.getNumberOfBuckets() > 1
@@ -223,6 +225,57 @@ class NotificationSectionsManager @Inject internal constructor(
@VisibleForTesting
fun updateSectionBoundaries() = updateSectionBoundaries("test")
+ private interface SectionUpdateState<out T : ExpandableView> {
+ val header: T
+ var currentPosition: Int?
+ var targetPosition: Int?
+ fun adjustViewPosition()
+ }
+
+ private fun <T : ExpandableView> expandableViewHeaderState(header: T): SectionUpdateState<T> =
+ object : SectionUpdateState<T> {
+ override val header = header
+ override var currentPosition: Int? = null
+ override var targetPosition: Int? = null
+
+ override fun adjustViewPosition() {
+ val target = targetPosition
+ val current = currentPosition
+ if (target == null) {
+ if (current != null) {
+ parent.removeView(header)
+ }
+ } else {
+ if (current == null) {
+ // If the header is animating away, it will still have a parent, so
+ // detach it first
+ // TODO: We should really cancel the active animations here. This will
+ // happen automatically when the view's intro animation starts, but
+ // it's a fragile link.
+ header.transientContainer?.removeTransientView(header)
+ header.transientContainer = null
+ parent.addView(header, target)
+ } else {
+ parent.changeViewPosition(header, target)
+ }
+ }
+ }
+ }
+
+ private fun <T : StackScrollerDecorView> decorViewHeaderState(
+ header: T
+ ): SectionUpdateState<T> {
+ val inner = expandableViewHeaderState(header)
+ return object : SectionUpdateState<T> by inner {
+ override fun adjustViewPosition() {
+ inner.adjustViewPosition()
+ if (targetPosition != null && currentPosition == null) {
+ header.isContentVisible = true
+ }
+ }
+ }
+ }
+
/**
* Should be called whenever notifs are added, removed, or updated. Updates section boundary
* bookkeeping and adds/moves/removes section headers if appropriate.
@@ -238,233 +291,136 @@ class NotificationSectionsManager @Inject internal constructor(
// Then, once we find the start of a new section, we track that position as the "target" for
// the section header, adjusted for the case where existing headers are in front of that
// target, but won't be once they are moved / removed after the pass has completed.
+
val showHeaders = statusBarStateController.state != StatusBarState.KEYGUARD
val usingPeopleFiltering = sectionsFeatureManager.isFilteringEnabled()
val usingMediaControls = sectionsFeatureManager.isMediaControlsEnabled()
- var peopleNotifsPresent = false
- var currentMediaControlsIdx = -1
- val mediaControlsTarget = if (usingMediaControls) 0 else -1
- var currentIncomingHeaderIdx = -1
- var incomingHeaderTarget = -1
- var currentPeopleHeaderIdx = -1
- var peopleHeaderTarget = -1
- var currentAlertingHeaderIdx = -1
- var alertingHeaderTarget = -1
- var currentGentleHeaderIdx = -1
- var gentleHeaderTarget = -1
+ val mediaState = mediaControlsView?.let(::expandableViewHeaderState)
+ val incomingState = incomingHeaderView?.let(::decorViewHeaderState)
+ val peopleState = peopleHeaderView?.let(::decorViewHeaderState)
+ val alertingState = alertingHeaderView?.let(::decorViewHeaderState)
+ val gentleState = silentHeaderView?.let(::decorViewHeaderState)
+
+ fun getSectionState(view: View): SectionUpdateState<ExpandableView>? = when {
+ view === mediaControlsView -> mediaState
+ view === incomingHeaderView -> incomingState
+ view === peopleHeaderView -> peopleState
+ view === alertingHeaderView -> alertingState
+ view === silentHeaderView -> gentleState
+ else -> null
+ }
+ val headersOrdered = sequenceOf(
+ mediaState, incomingState, peopleState, alertingState, gentleState
+ ).filterNotNull()
+
+ var peopleNotifsPresent = false
var lastNotifIndex = 0
- var lastIncomingIndex = -1
- var prev: ExpandableNotificationRow? = null
-
- for ((i, child) in parent.children.withIndex()) {
- when {
- // Track the existing positions of the headers
- child === incomingHeaderView -> {
- logger.logIncomingHeader(i)
- currentIncomingHeaderIdx = i
- }
- child === mediaControlsView -> {
- logger.logMediaControls(i)
- currentMediaControlsIdx = i
- }
- child === peopleHeaderView -> {
- logger.logConversationsHeader(i)
- currentPeopleHeaderIdx = i
- }
- child === alertingHeaderView -> {
- logger.logAlertingHeader(i)
- currentAlertingHeaderIdx = i
+ var nextBucket: Int? = null
+ var inIncomingSection = false
+
+ // Iterating backwards allows for easier construction of the Incoming section, as opposed
+ // to backtracking when a discontinuity in the sections is discovered.
+ // Iterating to -1 in order to support the case where a header is at the very top of the
+ // shade.
+ for (i in parent.childCount - 1 downTo -1) {
+ val child: View? = parent.getChildAt(i)
+ child?.let {
+ logShadeChild(i, child)
+ // If this child is a header, update the tracked positions
+ getSectionState(child)?.let { state ->
+ state.currentPosition = i
+ // If headers that should appear above this one in the shade already have a
+ // target index, then we need to decrement them in order to account for this one
+ // being either removed, or moved below them.
+ headersOrdered.takeUntil { it === state }
+ .forEach { it.targetPosition = it.targetPosition?.minus(1) }
}
- child === silentHeaderView -> {
- logger.logSilentHeader(i)
- currentGentleHeaderIdx = i
- }
- child !is ExpandableNotificationRow -> logger.logOther(i, child.javaClass)
- else -> {
- lastNotifIndex = i
- // Is there a section discontinuity? This usually occurs due to HUNs
- if (prev?.entry?.bucket?.let { it > child.entry.bucket } == true) {
- // Remove existing headers, and move the Incoming header if necessary
- incomingHeaderTarget = when {
- !showHeaders -> -1
- incomingHeaderTarget != -1 -> incomingHeaderTarget
- peopleHeaderTarget != -1 -> peopleHeaderTarget
- alertingHeaderTarget != -1 -> alertingHeaderTarget
- gentleHeaderTarget != -1 -> gentleHeaderTarget
- else -> 0
- }
- peopleHeaderTarget = -1
- alertingHeaderTarget = -1
- gentleHeaderTarget = -1
- // Walk backwards changing all previous notifications to the Incoming
- // section
- for (j in i - 1 downTo lastIncomingIndex + 1) {
- val prevChild = parent.getChildAt(j)
- if (prevChild is ExpandableNotificationRow) {
- prevChild.entry.bucket = BUCKET_HEADS_UP
- }
- }
- // Track the new bottom of the Incoming section
- lastIncomingIndex = i - 1
- }
- val isHeadsUp = child.isHeadsUp
- when (child.entry.bucket) {
- BUCKET_FOREGROUND_SERVICE -> logger.logForegroundService(i, isHeadsUp)
- BUCKET_PEOPLE -> {
- logger.logConversation(i, isHeadsUp)
- peopleNotifsPresent = true
- if (showHeaders && peopleHeaderTarget == -1) {
- peopleHeaderTarget = i
- // Offset the target if there are other headers before this that
- // will be moved.
- if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
- peopleHeaderTarget--
- }
- if (currentPeopleHeaderIdx != -1) {
- peopleHeaderTarget--
- }
- if (currentAlertingHeaderIdx != -1) {
- peopleHeaderTarget--
- }
- if (currentGentleHeaderIdx != -1) {
- peopleHeaderTarget--
- }
- }
- }
- BUCKET_ALERTING -> {
- logger.logAlerting(i, isHeadsUp)
- if (showHeaders && usingPeopleFiltering && alertingHeaderTarget == -1) {
- alertingHeaderTarget = i
- // Offset the target if there are other headers before this that
- // will be moved.
- if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
- alertingHeaderTarget--
- }
- if (currentPeopleHeaderIdx != -1 && peopleHeaderTarget == -1) {
- // People header will be removed
- alertingHeaderTarget--
- }
- if (currentAlertingHeaderIdx != -1) {
- alertingHeaderTarget--
- }
- if (currentGentleHeaderIdx != -1) {
- alertingHeaderTarget--
- }
- }
- }
- BUCKET_SILENT -> {
- logger.logSilent(i, isHeadsUp)
- if (showHeaders && gentleHeaderTarget == -1) {
- gentleHeaderTarget = i
- // Offset the target if there are other headers before this that
- // will be moved.
- if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
- gentleHeaderTarget--
- }
- if (currentPeopleHeaderIdx != -1 && peopleHeaderTarget == -1) {
- // People header will be removed
- gentleHeaderTarget--
- }
- if (currentAlertingHeaderIdx != -1 && alertingHeaderTarget == -1) {
- // Alerting header will be removed
- gentleHeaderTarget--
- }
- if (currentGentleHeaderIdx != -1) {
- gentleHeaderTarget--
- }
- }
- }
- }
+ }
+
+ val row = child as? ExpandableNotificationRow
+
+ // Is there a section discontinuity? This usually occurs due to HUNs
+ inIncomingSection = inIncomingSection || nextBucket?.let { next ->
+ row?.entry?.bucket?.let { curr -> next < curr }
+ } == true
- prev = child
+ if (inIncomingSection) {
+ // Update the bucket to reflect that it's being placed in the Incoming section
+ row?.entry?.bucket = BUCKET_HEADS_UP
+ }
+
+ // Insert a header in front of the next row, if there's a boundary between it and this
+ // row, or if it is the topmost row.
+ val isSectionBoundary = nextBucket != null &&
+ (child == null || row != null && nextBucket != row.entry.bucket)
+ if (isSectionBoundary && showHeaders) {
+ when (nextBucket) {
+ BUCKET_HEADS_UP -> incomingState?.targetPosition = i + 1
+ BUCKET_PEOPLE -> peopleState?.targetPosition = i + 1
+ BUCKET_ALERTING -> alertingState?.targetPosition = i + 1
+ BUCKET_SILENT -> gentleState?.targetPosition = i + 1
}
}
- }
- if (showHeaders && usingPeopleFiltering && peopleHubVisible && peopleHeaderTarget == -1) {
- // Insert the people header even if there are no people visible, in order to show
- // the hub. Put it directly above the next header.
- peopleHeaderTarget = when {
- alertingHeaderTarget != -1 -> alertingHeaderTarget
- gentleHeaderTarget != -1 -> gentleHeaderTarget
- else -> lastNotifIndex // Put it at the end of the list.
+ row ?: continue
+
+ // Check if there are any people notifications
+ peopleNotifsPresent = peopleNotifsPresent || row.entry.bucket == BUCKET_PEOPLE
+
+ if (nextBucket == null) {
+ lastNotifIndex = i
}
+ nextBucket = row.entry.bucket
+ }
+
+ if (showHeaders && usingPeopleFiltering && peopleHubVisible) {
+ peopleState?.targetPosition = peopleState?.targetPosition
+ // Insert the people header even if there are no people visible, in order to
+ // show the hub. Put it directly above the next header.
+ ?: alertingState?.targetPosition
+ ?: gentleState?.targetPosition
+ // Put it at the end of the list.
+ ?: lastNotifIndex
+
// Offset the target to account for the current position of the people header.
- if (currentPeopleHeaderIdx != -1 && currentPeopleHeaderIdx < peopleHeaderTarget) {
- peopleHeaderTarget--
+ peopleState?.targetPosition = peopleState?.currentPosition?.let { current ->
+ peopleState?.targetPosition?.let { target ->
+ if (current < target) target - 1 else target
+ }
}
}
+ mediaState?.targetPosition = if (usingMediaControls) 0 else null
+
logger.logStr("New header target positions:")
- logger.logIncomingHeader(incomingHeaderTarget)
- logger.logMediaControls(mediaControlsTarget)
- logger.logConversationsHeader(peopleHeaderTarget)
- logger.logAlertingHeader(alertingHeaderTarget)
- logger.logSilentHeader(gentleHeaderTarget)
-
- // Add headers in reverse order to preserve indices
- silentHeaderView?.let {
- adjustHeaderVisibilityAndPosition(gentleHeaderTarget, it, currentGentleHeaderIdx)
- }
- alertingHeaderView?.let {
- adjustHeaderVisibilityAndPosition(alertingHeaderTarget, it, currentAlertingHeaderIdx)
- }
- peopleHeaderView?.let {
- adjustHeaderVisibilityAndPosition(peopleHeaderTarget, it, currentPeopleHeaderIdx)
- }
- incomingHeaderView?.let {
- adjustHeaderVisibilityAndPosition(incomingHeaderTarget, it, currentIncomingHeaderIdx)
- }
- mediaControlsView?.let {
- adjustViewPosition(mediaControlsTarget, it, currentMediaControlsIdx)
- }
+ logger.logMediaControls(mediaState?.targetPosition ?: -1)
+ logger.logIncomingHeader(incomingState?.targetPosition ?: -1)
+ logger.logConversationsHeader(peopleState?.targetPosition ?: -1)
+ logger.logAlertingHeader(alertingState?.targetPosition ?: -1)
+ logger.logSilentHeader(gentleState?.targetPosition ?: -1)
+
+ // Update headers in reverse order to preserve indices, otherwise movements earlier in the
+ // list will affect the target indices of the headers later in the list.
+ headersOrdered.asIterable().reversed().forEach { it.adjustViewPosition() }
logger.logStr("Final order:")
logShadeContents()
logger.logStr("Section boundary update complete")
// Update headers to reflect state of section contents
- silentHeaderView?.setAreThereDismissableGentleNotifs(
- parent.hasActiveClearableNotifications(NotificationStackScrollLayout.ROWS_GENTLE)
- )
- peopleHeaderView?.canSwipe = showHeaders && peopleHubVisible && !peopleNotifsPresent
- if (peopleHeaderTarget != currentPeopleHeaderIdx) {
- peopleHeaderView?.resetTranslation()
- }
- }
-
- private fun adjustHeaderVisibilityAndPosition(
- targetPosition: Int,
- header: StackScrollerDecorView,
- currentPosition: Int
- ) {
- adjustViewPosition(targetPosition, header, currentPosition)
- if (targetPosition != -1 && currentPosition == -1) {
- header.isContentVisible = true
+ silentHeaderView?.run {
+ val hasActiveClearableNotifications = this@NotificationSectionsManager.parent
+ .hasActiveClearableNotifications(NotificationStackScrollLayout.ROWS_GENTLE)
+ setAreThereDismissableGentleNotifs(hasActiveClearableNotifications)
}
- }
-
- private fun adjustViewPosition(
- targetPosition: Int,
- view: ExpandableView,
- currentPosition: Int
- ) {
- if (targetPosition == -1) {
- if (currentPosition != -1) {
- parent.removeView(view)
- }
- } else {
- if (currentPosition == -1) {
- // If the header is animating away, it will still have a parent, so detach it first
- // TODO: We should really cancel the active animations here. This will happen
- // automatically when the view's intro animation starts, but it's a fragile link.
- view.transientContainer?.removeTransientView(view)
- view.transientContainer = null
- parent.addView(view, targetPosition)
- } else {
- parent.changeViewPosition(view, targetPosition)
+ peopleHeaderView?.run {
+ canSwipe = showHeaders && peopleHubVisible && !peopleNotifsPresent
+ peopleState?.targetPosition?.let { targetPosition ->
+ if (targetPosition != peopleState.currentPosition) {
+ resetTranslation()
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 825919f17661..fc8c8dbba7fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -19,7 +19,6 @@ import android.content.res.Resources;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
-import android.os.UserHandle;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -35,7 +34,6 @@ import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DataSaverController.Listener;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotController.Callback;
-import com.android.systemui.util.UserAwareController;
import java.util.ArrayList;
import java.util.Objects;
@@ -45,7 +43,7 @@ import javax.inject.Inject;
/**
* Manages which tiles should be automatically added to QS.
*/
-public class AutoTileManager implements UserAwareController {
+public class AutoTileManager {
private static final String TAG = "AutoTileManager";
public static final String HOTSPOT = "hotspot";
@@ -54,9 +52,7 @@ public class AutoTileManager implements UserAwareController {
public static final String WORK = "work";
public static final String NIGHT = "night";
public static final String CAST = "cast";
- static final String SETTING_SEPARATOR = ":";
-
- private UserHandle mCurrentUser;
+ public static final String SETTING_SEPARATOR = ":";
private final Context mContext;
private final QSTileHost mHost;
@@ -70,56 +66,43 @@ public class AutoTileManager implements UserAwareController {
private final ArrayList<AutoAddSetting> mAutoAddSettingList = new ArrayList<>();
@Inject
- public AutoTileManager(Context context, AutoAddTracker.Builder autoAddTrackerBuilder,
- QSTileHost host,
+ public AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
@Background Handler handler,
HotspotController hotspotController,
DataSaverController dataSaverController,
ManagedProfileController managedProfileController,
NightDisplayListener nightDisplayListener,
CastController castController) {
+ mAutoTracker = autoAddTracker;
mContext = context;
mHost = host;
- mCurrentUser = mHost.getUserContext().getUser();
- mAutoTracker = autoAddTrackerBuilder.setUserId(mCurrentUser.getIdentifier()).build();
mHandler = handler;
mHotspotController = hotspotController;
mDataSaverController = dataSaverController;
mManagedProfileController = managedProfileController;
mNightDisplayListener = nightDisplayListener;
mCastController = castController;
-
- populateSettingsList();
- startControllersAndSettingsListeners();
- }
-
- protected void startControllersAndSettingsListeners() {
if (!mAutoTracker.isAdded(HOTSPOT)) {
- mHotspotController.addCallback(mHotspotCallback);
+ hotspotController.addCallback(mHotspotCallback);
}
if (!mAutoTracker.isAdded(SAVER)) {
- mDataSaverController.addCallback(mDataSaverListener);
+ dataSaverController.addCallback(mDataSaverListener);
}
if (!mAutoTracker.isAdded(WORK)) {
- mManagedProfileController.addCallback(mProfileCallback);
+ managedProfileController.addCallback(mProfileCallback);
}
if (!mAutoTracker.isAdded(NIGHT)
&& ColorDisplayManager.isNightDisplayAvailable(mContext)) {
- mNightDisplayListener.setCallback(mNightDisplayCallback);
+ nightDisplayListener.setCallback(mNightDisplayCallback);
}
if (!mAutoTracker.isAdded(CAST)) {
- mCastController.addCallback(mCastCallback);
- }
-
- int settingsN = mAutoAddSettingList.size();
- for (int i = 0; i < settingsN; i++) {
- if (!mAutoTracker.isAdded(mAutoAddSettingList.get(i).mSpec)) {
- mAutoAddSettingList.get(i).setListening(true);
- }
+ castController.addCallback(mCastCallback);
}
+ populateSettingsList();
}
- protected void stopListening() {
+ public void destroy() {
+ mAutoTracker.destroy();
mHotspotController.removeCallback(mHotspotCallback);
mDataSaverController.removeCallback(mDataSaverListener);
mManagedProfileController.removeCallback(mProfileCallback);
@@ -133,11 +116,6 @@ public class AutoTileManager implements UserAwareController {
}
}
- public void destroy() {
- stopListening();
- mAutoTracker.destroy();
- }
-
/**
* Populates a list with the pairs setting:spec in the config resource.
* <p>
@@ -159,39 +137,17 @@ public class AutoTileManager implements UserAwareController {
if (split.length == 2) {
String setting = split[0];
String spec = split[1];
- // Populate all the settings. As they may not have been added in other users
- AutoAddSetting s = new AutoAddSetting(mContext, mHandler, setting, spec);
- mAutoAddSettingList.add(s);
+ if (!mAutoTracker.isAdded(spec)) {
+ AutoAddSetting s = new AutoAddSetting(mContext, mHandler, setting, spec);
+ mAutoAddSettingList.add(s);
+ s.setListening(true);
+ }
} else {
Log.w(TAG, "Malformed item in array: " + tile);
}
}
}
- @Override
- public void changeUser(UserHandle newUser) {
- if (!Thread.currentThread().equals(mHandler.getLooper().getThread())) {
- mHandler.post(() -> changeUser(newUser));
- return;
- }
- if (newUser.getIdentifier() == mCurrentUser.getIdentifier()) {
- return;
- }
- stopListening();
- mCurrentUser = newUser;
- int settingsN = mAutoAddSettingList.size();
- for (int i = 0; i < settingsN; i++) {
- mAutoAddSettingList.get(i).setUserId(newUser.getIdentifier());
- }
- mAutoTracker.changeUser(newUser);
- startControllersAndSettingsListeners();
- }
-
- @Override
- public int getCurrentUserId() {
- return mCurrentUser.getIdentifier();
- }
-
public void unmarkTileAsAutoAdded(String tabSpec) {
mAutoTracker.setTileRemoved(tabSpec);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 11022bbcb7ea..df121f0faaf9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -323,6 +323,20 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
buttonDispatcher.setAlpha(forceVisible ? 1f : alpha, animate);
}
}
+
+ @Override
+ public void onOverviewShown(boolean fromHome) {
+ // If the overview has fixed orientation that may change display to natural rotation,
+ // we don't want the user rotation to be reset. So after user returns to application,
+ // it can keep in the original rotation.
+ mNavigationBarView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
+ }
+
+ @Override
+ public void onToggleRecentApps() {
+ // The same case as onOverviewShown but only for 3-button navigation.
+ mNavigationBarView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
+ }
};
private NavigationBarTransitions.DarkIntensityListener mOrientationHandleIntensityListener =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 9e7bf6220546..e720d820fd76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -1328,11 +1328,15 @@ public class NotificationPanelViewController extends PanelViewController {
*
* @param velocity unit is in px / millis
*/
- public void stopWaitingForOpenPanelGesture(final float velocity) {
+ public void stopWaitingForOpenPanelGesture(boolean cancel, final float velocity) {
if (mExpectingSynthesizedDown) {
mExpectingSynthesizedDown = false;
- maybeVibrateOnOpening();
- fling(velocity > 1f ? 1000f * velocity : 0, true /* expand */);
+ if (cancel) {
+ collapse(false /* delayed */, 1.0f /* speedUpFactor */);
+ } else {
+ maybeVibrateOnOpening();
+ fling(velocity > 1f ? 1000f * velocity : 0, true /* expand */);
+ }
onTrackingStopped(false);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
index de9c745cb357..59b10e416b03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
@@ -74,6 +74,7 @@ public class RotationButtonController {
private Consumer<Integer> mRotWatcherListener;
private boolean mListenersRegistered = false;
private boolean mIsNavigationBarShowing;
+ private boolean mSkipOverrideUserLockPrefsOnce;
private final Runnable mRemoveRotationProposal =
() -> setRotateSuggestionButtonState(false /* visible */);
@@ -349,7 +350,20 @@ public class RotationButtonController {
mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_SHOWN);
}
+ /**
+ * Makes {@link #shouldOverrideUserLockPrefs} always return {@code false} once. It is used to
+ * avoid losing original user rotation when display rotation is changed by entering the fixed
+ * orientation overview.
+ */
+ void setSkipOverrideUserLockPrefsOnce() {
+ mSkipOverrideUserLockPrefsOnce = true;
+ }
+
private boolean shouldOverrideUserLockPrefs(final int rotation) {
+ if (mSkipOverrideUserLockPrefsOnce) {
+ mSkipOverrideUserLockPrefsOnce = false;
+ return false;
+ }
// Only override user prefs when returning to the natural rotation (normally portrait).
// Don't let apps that force landscape or 180 alter user lock.
return rotation == NATURAL_ROTATION;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e2714af33247..a21ca5320518 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1772,6 +1772,9 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public void setPanelExpanded(boolean isExpanded) {
+ if (mPanelExpanded != isExpanded) {
+ mNotificationLogger.onPanelExpandedChanged(isExpanded);
+ }
mPanelExpanded = isExpanded;
updateHideIconsForBouncer(false /* animate */);
mNotificationShadeWindowController.setPanelExpanded(isExpanded);
@@ -2090,7 +2093,7 @@ public class StatusBar extends SystemUI implements DemoMode,
/**
* Called when another window is about to transfer it's input focus.
*/
- public void onInputFocusTransfer(boolean start, float velocity) {
+ public void onInputFocusTransfer(boolean start, boolean cancel, float velocity) {
if (!mCommandQueue.panelsEnabled()) {
return;
}
@@ -2098,7 +2101,7 @@ public class StatusBar extends SystemUI implements DemoMode,
if (start) {
mNotificationPanelViewController.startWaitingForOpenPanelGesture();
} else {
- mNotificationPanelViewController.stopWaitingForOpenPanelGesture(velocity);
+ mNotificationPanelViewController.stopWaitingForOpenPanelGesture(cancel, velocity);
}
}
@@ -2878,7 +2881,6 @@ public class StatusBar extends SystemUI implements DemoMode,
}
// Visibility reporting
-
protected void handleVisibleToUserChanged(boolean visibleToUser) {
if (visibleToUser) {
handleVisibleToUserChangedImpl(visibleToUser);
@@ -2900,12 +2902,12 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- /**
- * The LEDs are turned off when the notification panel is shown, even just a little bit.
- * See also StatusBar.setPanelExpanded for another place where we attempt to do this.
- */
- private void handleVisibleToUserChangedImpl(boolean visibleToUser) {
+ // Visibility reporting
+
+ void handleVisibleToUserChangedImpl(boolean visibleToUser) {
if (visibleToUser) {
+ /* The LEDs are turned off when the notification panel is shown, even just a little bit.
+ * See also StatusBar.setPanelExpanded for another place where we attempt to do this. */
boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
boolean clearNotificationEffects =
!mPresenter.isPresenterFullyCollapsed() &&
@@ -3982,7 +3984,7 @@ public class StatusBar extends SystemUI implements DemoMode,
} else if (mIsKeyguard && !unlocking) {
mScrimController.transitionTo(ScrimState.KEYGUARD);
} else if (mBubbleController.isStackExpanded()) {
- mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED);
+ mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED, mUnlockScrimCallback);
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt b/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
index c91033e4745a..631ea9d61361 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
@@ -22,4 +22,14 @@ import android.view.ViewGroup
val ViewGroup.children
get() = sequence {
for (i in 0 until childCount) yield(getChildAt(i))
- } \ No newline at end of file
+ }
+
+/** Inclusive version of [Iterable.takeWhile] */
+fun <T> Sequence<T>.takeUntil(pred: (T) -> Boolean): Sequence<T> = sequence {
+ for (x in this@takeUntil) {
+ yield(x)
+ if (pred(x)) {
+ break
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt b/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt
index accb81eae32a..1a25c84a7965 100644
--- a/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt
@@ -19,6 +19,22 @@ package com.android.systemui.util
import android.util.SparseArray
/**
+ * Transforms a sequence of Key/Value pairs into a SparseArray.
+ *
+ * See [kotlin.collections.toMap].
+ */
+fun <T> Sequence<Pair<Int, T>>.toSparseArray(size: Int = -1): SparseArray<T> {
+ val sparseArray = when {
+ size < 0 -> SparseArray<T>()
+ else -> SparseArray<T>(size)
+ }
+ for ((i, v) in this) {
+ sparseArray.put(i, v)
+ }
+ return sparseArray
+}
+
+/**
* Transforms an [Array] into a [SparseArray], by applying each element to [keySelector] in order to
* generate the index at which it will be placed. If two elements produce the same index, the latter
* replaces the former in the final result.
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
index 701ff5ecf8a1..806d9d8e158a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
@@ -37,6 +37,7 @@ class TransitionLayout @JvmOverloads constructor(
) : ConstraintLayout(context, attrs, defStyleAttr) {
private val originalGoneChildrenSet: MutableSet<Int> = mutableSetOf()
+ private val originalViewAlphas: MutableMap<Int, Float> = mutableMapOf()
private var measureAsConstraint: Boolean = false
private var currentState: TransitionViewState = TransitionViewState()
private var updateScheduled = false
@@ -67,6 +68,7 @@ class TransitionLayout @JvmOverloads constructor(
if (child.visibility == GONE) {
originalGoneChildrenSet.add(child.id)
}
+ originalViewAlphas[child.id] = child.alpha
}
}
@@ -198,6 +200,8 @@ class TransitionLayout @JvmOverloads constructor(
if (originalGoneChildrenSet.contains(child.id)) {
child.visibility = View.GONE
}
+ // Reset the alphas, to only have the alphas present from the constraintset
+ child.alpha = originalViewAlphas[child.id] ?: 1.0f
}
// Let's now apply the constraintSet to get the full state
constraintSet.applyTo(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 59f8c4e329a4..36398a6fc122 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -304,6 +304,10 @@ public class BubbleControllerTest extends SysuiTestCase {
public void testPromoteBubble_autoExpand() throws Exception {
mBubbleController.updateBubble(mRow2.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
+ when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
+ .thenReturn(mRow.getEntry());
+ when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
+ .thenReturn(mRow2.getEntry());
mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
@@ -331,6 +335,10 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleController.updateBubble(mRow2.getEntry());
mBubbleController.updateBubble(mRow.getEntry(), /* suppressFlyout */
false, /* showInShade */ true);
+ when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
+ .thenReturn(mRow.getEntry());
+ when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
+ .thenReturn(mRow2.getEntry());
mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
@@ -433,15 +441,16 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mSysUiStateBubblesExpanded);
// Last added is the one that is expanded
- assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
+ assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow2.getEntry()));
// Switch which bubble is expanded
- mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
+ mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(
+ mRow.getEntry().getKey()));
mBubbleData.setExpanded(true);
- assertEquals(mRow.getEntry(),
- mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+ stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -543,27 +552,27 @@ public class BubbleControllerTest extends SysuiTestCase {
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
// Last added is the one that is expanded
- assertEquals(mRow2.getEntry(),
- mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+ stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow2.getEntry()));
// Dismiss currently expanded
mBubbleController.removeBubble(
- mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey())
- .getEntry().getKey(),
+ mBubbleData.getBubbleInStackWithKey(
+ stackView.getExpandedBubble().getKey()).getKey(),
BubbleController.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
// Make sure first bubble is selected
- assertEquals(mRow.getEntry(),
- mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+ stackView.getExpandedBubble().getKey()).getKey());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
// Dismiss that one
mBubbleController.removeBubble(
- mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey())
- .getEntry().getKey(),
+ mBubbleData.getBubbleInStackWithKey(
+ stackView.getExpandedBubble().getKey()).getKey(),
BubbleController.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens
@@ -839,6 +848,12 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow2.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
mBubbleController.updateBubble(
mRow3.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
+ when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
+ .thenReturn(mRow.getEntry());
+ when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
+ .thenReturn(mRow2.getEntry());
+ when(mNotificationEntryManager.getPendingOrActiveNotif(mRow3.getEntry().getKey()))
+ .thenReturn(mRow3.getEntry());
assertEquals(mBubbleData.getBubbles().size(), 3);
mBubbleData.setMaxOverflowBubbles(1);
@@ -908,6 +923,8 @@ public class BubbleControllerTest extends SysuiTestCase {
// GIVEN a group summary with a bubble child
ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
+ when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+ .thenReturn(groupedBubble.getEntry());
mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
groupSummary.addChildNotification(groupedBubble);
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
@@ -927,6 +944,8 @@ public class BubbleControllerTest extends SysuiTestCase {
ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
+ when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+ .thenReturn(groupedBubble.getEntry());
groupSummary.addChildNotification(groupedBubble);
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
@@ -948,6 +967,8 @@ public class BubbleControllerTest extends SysuiTestCase {
// GIVEN a group summary with two (non-bubble) children and one bubble child
ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(2);
ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
+ when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+ .thenReturn(groupedBubble.getEntry());
mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
groupSummary.addChildNotification(groupedBubble);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
index 72f816ff56b5..be03923e7264 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
@@ -86,8 +86,7 @@ public class BubbleTest extends SysuiTestCase {
final String msg = "Hello there!";
doReturn(Notification.Style.class).when(mNotif).getNotificationStyle();
mExtras.putCharSequence(Notification.EXTRA_TEXT, msg);
- assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mContext,
- mEntry).message);
+ assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mEntry).message);
}
@Test
@@ -98,8 +97,7 @@ public class BubbleTest extends SysuiTestCase {
mExtras.putCharSequence(Notification.EXTRA_BIG_TEXT, msg);
// Should be big text, not the small text.
- assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mContext,
- mEntry).message);
+ assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mEntry).message);
}
@Test
@@ -107,8 +105,7 @@ public class BubbleTest extends SysuiTestCase {
doReturn(Notification.MediaStyle.class).when(mNotif).getNotificationStyle();
// Media notifs don't get update messages.
- assertNull(BubbleViewInfoTask.extractFlyoutMessage(mContext,
- mEntry).message);
+ assertNull(BubbleViewInfoTask.extractFlyoutMessage(mEntry).message);
}
@Test
@@ -124,7 +121,7 @@ public class BubbleTest extends SysuiTestCase {
// Should be the last one only.
assertEquals("Really? I prefer them that way.",
- BubbleViewInfoTask.extractFlyoutMessage(mContext, mEntry).message);
+ BubbleViewInfoTask.extractFlyoutMessage(mEntry).message);
}
@Test
@@ -139,11 +136,8 @@ public class BubbleTest extends SysuiTestCase {
"Oh, hello!", 0, "Mady").toBundle()});
// Should be the last one only.
- assertEquals("Oh, hello!",
- BubbleViewInfoTask.extractFlyoutMessage(mContext, mEntry).message);
- assertEquals("Mady",
- BubbleViewInfoTask.extractFlyoutMessage(mContext,
- mEntry).senderName);
+ assertEquals("Oh, hello!", BubbleViewInfoTask.extractFlyoutMessage(mEntry).message);
+ assertEquals("Mady", BubbleViewInfoTask.extractFlyoutMessage(mEntry).senderName);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 58e06b5178c6..1c70db3a548e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -302,6 +302,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
public void testRemoveBubble_withDismissedNotif_notInOverflow() {
mEntryListener.onEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
+ when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
+ .thenReturn(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
@@ -388,14 +390,14 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
true, mRow.getEntry().getKey());
// Last added is the one that is expanded
- assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
+ assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry()));
// Switch which bubble is expanded
mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
mBubbleData.setExpanded(true);
- assertEquals(mRow.getEntry(),
- mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+ stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -488,27 +490,27 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
// Last added is the one that is expanded
- assertEquals(mRow2.getEntry(),
- mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+ stackView.getExpandedBubble().getKey()).getKey());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow2.getEntry()));
// Dismiss currently expanded
mBubbleController.removeBubble(
mBubbleData.getBubbleInStackWithKey(
- stackView.getExpandedBubble().getKey()).getEntry().getKey(),
+ stackView.getExpandedBubble().getKey()).getKey(),
BubbleController.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
// Make sure first bubble is selected
- assertEquals(mRow.getEntry(),
- mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+ assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+ stackView.getExpandedBubble().getKey()).getKey());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
// Dismiss that one
mBubbleController.removeBubble(
mBubbleData.getBubbleInStackWithKey(
- stackView.getExpandedBubble().getKey()).getEntry().getKey(),
+ stackView.getExpandedBubble().getKey()).getKey(),
BubbleController.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens
@@ -767,6 +769,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
mEntryListener.onEntryAdded(groupedBubble.getEntry());
+ when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+ .thenReturn(groupedBubble.getEntry());
groupSummary.addChildNotification(groupedBubble);
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
@@ -785,6 +789,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
mEntryListener.onEntryAdded(groupedBubble.getEntry());
+ when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+ .thenReturn(groupedBubble.getEntry());
groupSummary.addChildNotification(groupedBubble);
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
@@ -807,6 +813,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(2);
ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
mEntryListener.onEntryAdded(groupedBubble.getEntry());
+ when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+ .thenReturn(groupedBubble.getEntry());
groupSummary.addChildNotification(groupedBubble);
// WHEN the summary is dismissed
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
index 1d02b8dba910..9b8fd11febe3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -32,7 +32,7 @@ class BubblePersistentRepositoryTest : SysuiTestCase() {
private val bubbles = listOf(
BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0),
- BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428, "title"),
BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0)
)
private lateinit var repository: BubblePersistentRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
index f9d611c2bb33..76c58339726c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -37,9 +37,10 @@ class BubbleVolatileRepositoryTest : SysuiTestCase() {
private val user0 = UserHandle.of(0)
private val user10 = UserHandle.of(10)
- private val bubble1 = BubbleEntity(0, PKG_MESSENGER, "shortcut-1", "k1", 120, 0)
- private val bubble2 = BubbleEntity(10, PKG_CHAT, "alice and bob", "k2", 0, 16537428)
- private val bubble3 = BubbleEntity(0, PKG_MESSENGER, "shortcut-2", "k3", 120, 0)
+ private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0)
+ private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob",
+ "key-2", 0, 16537428, "title")
+ private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0)
private val bubbles = listOf(bubble1, bubble2, bubble3)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
index 49467874dd8b..81687c7fbe1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
@@ -31,17 +31,17 @@ import java.io.ByteArrayOutputStream
class BubbleXmlHelperTest : SysuiTestCase() {
private val bubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0),
- BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0)
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title"),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0)
)
@Test
fun testWriteXml() {
val expectedEntries = """
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
- <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" />
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
""".trimIndent()
ByteArrayOutputStream().use {
writeXml(it, bubbles)
@@ -54,12 +54,12 @@ class BubbleXmlHelperTest : SysuiTestCase() {
@Test
fun testReadXml() {
val src = """
- <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
- <bs>
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
- <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" />
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
- </bs>
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<bs>
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
+</bs>
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
assertEquals("failed parsing bubbles from xml\n$src", bubbles, actual)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index 329af2b7f62b..3c1cc232f5c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -438,6 +438,9 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
GlobalActionsDialog.ActionsDialog dialog = mGlobalActionsDialog.mDialog;
assertThat(dialog).isNotNull();
assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.VISIBLE);
+
+ // Dismiss the dialog so that it does not pollute other tests
+ mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
}
@Test
@@ -455,6 +458,9 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
GlobalActionsDialog.ActionsDialog dialog = mGlobalActionsDialog.mDialog;
assertThat(dialog).isNotNull();
assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.GONE);
+
+ // Dismiss the dialog so that it does not pollute other tests
+ mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
}
@Test
@@ -473,6 +479,9 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
GlobalActionsDialog.ActionsDialog dialog = mGlobalActionsDialog.mDialog;
assertThat(dialog).isNotNull();
assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.GONE);
+
+ // Dismiss the dialog so that it does not pollute other tests
+ mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
}
private void setupDefaultActions() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
index 61f5a7bdd3b7..0ae9461d38b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
@@ -21,7 +21,6 @@ import static com.android.systemui.statusbar.phone.AutoTileManager.WORK;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -41,8 +40,6 @@ import org.junit.runner.RunWith;
@SmallTest
public class AutoAddTrackerTest extends SysuiTestCase {
- private static final int USER = 0;
-
private AutoAddTracker mAutoTracker;
@Before
@@ -54,7 +51,7 @@ public class AutoAddTrackerTest extends SysuiTestCase {
public void testMigration() {
Prefs.putBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true);
Prefs.putBoolean(mContext, Key.QS_WORK_ADDED, true);
- mAutoTracker = new AutoAddTracker(mContext, USER);
+ mAutoTracker = new AutoAddTracker(mContext);
assertTrue(mAutoTracker.isAdded(SAVER));
assertTrue(mAutoTracker.isAdded(WORK));
@@ -71,7 +68,7 @@ public class AutoAddTrackerTest extends SysuiTestCase {
@Test
public void testChangeFromBackup() {
- mAutoTracker = new AutoAddTracker(mContext, USER);
+ mAutoTracker = new AutoAddTracker(mContext);
assertFalse(mAutoTracker.isAdded(SAVER));
@@ -85,7 +82,7 @@ public class AutoAddTrackerTest extends SysuiTestCase {
@Test
public void testSetAdded() {
- mAutoTracker = new AutoAddTracker(mContext, USER);
+ mAutoTracker = new AutoAddTracker(mContext);
assertFalse(mAutoTracker.isAdded(SAVER));
mAutoTracker.setTileAdded(SAVER);
@@ -97,35 +94,16 @@ public class AutoAddTrackerTest extends SysuiTestCase {
@Test
public void testPersist() {
- mAutoTracker = new AutoAddTracker(mContext, USER);
+ mAutoTracker = new AutoAddTracker(mContext);
assertFalse(mAutoTracker.isAdded(SAVER));
mAutoTracker.setTileAdded(SAVER);
mAutoTracker.destroy();
- mAutoTracker = new AutoAddTracker(mContext, USER);
+ mAutoTracker = new AutoAddTracker(mContext);
assertTrue(mAutoTracker.isAdded(SAVER));
mAutoTracker.destroy();
}
-
- @Test
- public void testIndependentUsers() {
- mAutoTracker = new AutoAddTracker(mContext, USER);
- mAutoTracker.setTileAdded(SAVER);
-
- mAutoTracker = new AutoAddTracker(mContext, USER + 1);
- assertFalse(mAutoTracker.isAdded(SAVER));
- }
-
- @Test
- public void testChangeUser() {
- mAutoTracker = new AutoAddTracker(mContext, USER);
- mAutoTracker.setTileAdded(SAVER);
-
- mAutoTracker = new AutoAddTracker(mContext, USER + 1);
- mAutoTracker.changeUser(UserHandle.of(USER));
- assertTrue(mAutoTracker.isAdded(SAVER));
- }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
new file mode 100644
index 000000000000..b63e66f1ebe3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.icon;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.Person
+import android.content.pm.LauncherApps
+import android.content.pm.ShortcutInfo
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.os.SystemClock
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner;
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapperTest.Companion.any
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+
+import org.junit.runner.RunWith;
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.anyInt
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class IconManagerTest: SysuiTestCase() {
+ companion object {
+ private const val TEST_PACKAGE_NAME = "test";
+ private const val TEST_UID = 0;
+ }
+
+
+ private var id = 0
+ private val context = InstrumentationRegistry.getTargetContext();
+ @Mock private lateinit var shortcut: ShortcutInfo
+ @Mock private lateinit var shortcutIc: Icon
+ @Mock private lateinit var messageIc: Icon
+ @Mock private lateinit var largeIc: Icon
+ @Mock private lateinit var smallIc: Icon
+ @Mock private lateinit var drawable: Drawable
+ @Mock private lateinit var row: ExpandableNotificationRow
+
+ @Mock private lateinit var notifCollection: CommonNotifCollection
+ @Mock private lateinit var launcherApps: LauncherApps
+
+ private val iconBuilder = IconBuilder(context)
+
+ private lateinit var iconManager: IconManager
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ `when`(shortcutIc.loadDrawableAsUser(any(), anyInt())).thenReturn(drawable)
+ `when`(messageIc.loadDrawableAsUser(any(), anyInt())).thenReturn(drawable)
+ `when`(largeIc.loadDrawableAsUser(any(), anyInt())).thenReturn(drawable)
+ `when`(smallIc.loadDrawableAsUser(any(), anyInt())).thenReturn(drawable)
+
+ `when`(shortcut.icon).thenReturn(shortcutIc)
+ `when`(launcherApps.getShortcutIcon(shortcut)).thenReturn(shortcutIc)
+
+ iconManager = IconManager(notifCollection, launcherApps, iconBuilder)
+ }
+
+ @Test
+ fun testCreateIcons_importantConversation_shortcutIcon() {
+ val entry = notificationEntry(true, true, true)
+ entry?.channel?.isImportantConversation = true
+ entry?.let {
+ iconManager.createIcons(it)
+ }
+ assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, shortcutIc)
+ }
+
+ @Test
+ fun testCreateIcons_importantConversation_messageIcon() {
+ val entry = notificationEntry(false, true, true)
+ entry?.channel?.isImportantConversation = true
+ entry?.let {
+ iconManager.createIcons(it)
+ }
+ assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, messageIc)
+ }
+
+ @Test
+ fun testCreateIcons_importantConversation_largeIcon() {
+ val entry = notificationEntry(false, false, true)
+ entry?.channel?.isImportantConversation = true
+ entry?.let {
+ iconManager.createIcons(it)
+ }
+ assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, largeIc)
+ }
+
+ @Test
+ fun testCreateIcons_importantConversation_smallIcon() {
+ val entry = notificationEntry(false, false, false)
+ entry?.channel?.isImportantConversation = true
+ entry?.let {
+ iconManager.createIcons(it)
+ }
+ assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, smallIc)
+ }
+
+ @Test
+ fun testCreateIcons_notImportantConversation() {
+ val entry = notificationEntry(true, true, true)
+ entry?.let {
+ iconManager.createIcons(it)
+ }
+ assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, smallIc)
+ }
+
+ @Test
+ fun testCreateIcons_sensitiveImportantConversation() {
+ val entry = notificationEntry(true, false, false)
+ entry?.setSensitive(true, true);
+ entry?.channel?.isImportantConversation = true
+ entry?.let {
+ iconManager.createIcons(it)
+ }
+ assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, shortcutIc)
+ assertEquals(entry?.icons?.shelfIcon?.sourceIcon, smallIc)
+ assertEquals(entry?.icons?.aodIcon?.sourceIcon, smallIc)
+ }
+
+ @Test
+ fun testUpdateIcons_sensitivityChange() {
+ val entry = notificationEntry(true, false, false)
+ entry?.channel?.isImportantConversation = true
+ entry?.setSensitive(true, true);
+ entry?.let {
+ iconManager.createIcons(it)
+ }
+ assertEquals(entry?.icons?.aodIcon?.sourceIcon, smallIc)
+ entry?.setSensitive(false, false);
+ entry?.let {
+ iconManager.updateIcons(it)
+ }
+ assertEquals(entry?.icons?.shelfIcon?.sourceIcon, shortcutIc)
+ }
+
+ private fun notificationEntry(
+ hasShortcut: Boolean,
+ hasMessage: Boolean,
+ hasLargeIcon: Boolean
+ ): NotificationEntry? {
+ val n = Notification.Builder(mContext, "id")
+ .setSmallIcon(smallIc)
+ .setContentTitle("Title")
+ .setContentText("Text")
+
+ if (hasMessage) {
+ n.style = Notification.MessagingStyle("")
+ .addMessage(Notification.MessagingStyle.Message(
+ "",
+ SystemClock.currentThreadTimeMillis(),
+ Person.Builder().setIcon(messageIc).build()
+ ))
+ }
+
+ if (hasLargeIcon) {
+ n.setLargeIcon(largeIc)
+ }
+
+ val builder = NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setId(id++)
+ .setNotification(n.build())
+ .setChannel(NotificationChannel("id", "", IMPORTANCE_DEFAULT))
+ .setUser(UserHandle(ActivityManager.getCurrentUser()))
+
+ if (hasShortcut) {
+ builder.setShortcutInfo(shortcut)
+ }
+
+ val entry = builder.build()
+ entry.row = row
+ entry.setSensitive(false, true);
+ return entry
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index a3a46f67ee40..06bad80d6f87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -20,6 +20,8 @@ import static com.android.systemui.statusbar.notification.stack.NotificationSect
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -42,6 +44,7 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -163,28 +166,61 @@ public class NotificationLoggerTest extends SysuiTestCase {
mUiBgExecutor.runAllReady();
Mockito.reset(mBarService);
- mLogger.stopNotificationLogging();
+ setStateAsleep();
+ mLogger.onDozingChanged(false); // Wake to lockscreen
+ mLogger.onDozingChanged(true); // And go back to sleep, turning off logging
mUiBgExecutor.runAllReady();
// The visibility objects are recycled by NotificationLogger, so we can't use specific
// matchers here.
verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
}
+ private void setStateAsleep() {
+ mLogger.onPanelExpandedChanged(true);
+ mLogger.onDozingChanged(true);
+ mLogger.onStateChanged(StatusBarState.KEYGUARD);
+ }
+
+ private void setStateAwake() {
+ mLogger.onPanelExpandedChanged(false);
+ mLogger.onDozingChanged(false);
+ mLogger.onStateChanged(StatusBarState.SHADE);
+ }
+
+ @Test
+ public void testLogPanelShownOnWake() {
+ when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
+ setStateAsleep();
+ mLogger.onDozingChanged(false); // Wake to lockscreen
+ assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
+ assertTrue(mNotificationPanelLoggerFake.get(0).isLockscreen);
+ assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
+ Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
+ assertEquals(TEST_PACKAGE_NAME, n.packageName);
+ assertEquals(TEST_UID, n.uid);
+ assertEquals(1, n.instanceId);
+ assertFalse(n.isGroupSummary);
+ assertEquals(1 + BUCKET_ALERTING, n.section);
+ }
+
@Test
- public void testLogPanelShownOnLoggingStart() {
+ public void testLogPanelShownOnShadePull() {
when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
- mLogger.startNotificationLogging();
+ setStateAwake();
+ // Now expand panel
+ mLogger.onPanelExpandedChanged(true);
assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
- assertEquals(false, mNotificationPanelLoggerFake.get(0).isLockscreen);
+ assertFalse(mNotificationPanelLoggerFake.get(0).isLockscreen);
assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
assertEquals(TEST_PACKAGE_NAME, n.packageName);
assertEquals(TEST_UID, n.uid);
assertEquals(1, n.instanceId);
- assertEquals(false, n.isGroupSummary);
+ assertFalse(n.isGroupSummary);
assertEquals(1 + BUCKET_ALERTING, n.section);
}
+
@Test
public void testLogPanelShownHandlesNullInstanceIds() {
// Construct a NotificationEntry like mEntry, but with a null instance id.
@@ -198,7 +234,8 @@ public class NotificationLoggerTest extends SysuiTestCase {
entry.setRow(mRow);
when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry));
- mLogger.startNotificationLogging();
+ setStateAsleep();
+ mLogger.onDozingChanged(false); // Wake to lockscreen
assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index c55391a387d8..243503d1d8a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -403,11 +403,11 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
enablePeopleFiltering();
setupMockStack(
- PERSON.headsUp(), // personHeaderTarget = 0
- INCOMING_HEADER, // currentIncomingHeaderIdx = 1
- ALERTING.headsUp(), // alertingHeaderTarget = 1
- PEOPLE_HEADER, // currentPeopleHeaderIdx = 3
- PERSON //
+ PERSON.headsUp(),
+ INCOMING_HEADER,
+ ALERTING.headsUp(),
+ PEOPLE_HEADER,
+ PERSON
);
mSectionsManager.updateSectionBoundaries();
@@ -520,6 +520,70 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
ChildType.GENTLE);
}
+ @Test
+ public void testRemoveIncomingHeader() {
+ enablePeopleFiltering();
+ enableMediaControls();
+
+ setupMockStack(
+ MEDIA_CONTROLS,
+ INCOMING_HEADER,
+ PERSON,
+ ALERTING,
+ PEOPLE_HEADER,
+ ALERTING_HEADER,
+ ALERTING,
+ ALERTING,
+ GENTLE_HEADER,
+ GENTLE,
+ GENTLE
+ );
+
+ mSectionsManager.updateSectionBoundaries();
+
+ verifyMockStack(
+ ChildType.MEDIA_CONTROLS,
+ ChildType.PEOPLE_HEADER,
+ ChildType.PERSON,
+ ChildType.ALERTING_HEADER,
+ ChildType.ALERTING,
+ ChildType.ALERTING,
+ ChildType.ALERTING,
+ ChildType.GENTLE_HEADER,
+ ChildType.GENTLE,
+ ChildType.GENTLE
+ );
+ }
+
+ @Test
+ public void testExpandIncomingSection() {
+ enablePeopleFiltering();
+
+ setupMockStack(
+ INCOMING_HEADER,
+ PERSON,
+ ALERTING,
+ PEOPLE_HEADER,
+ ALERTING,
+ PERSON,
+ ALERTING_HEADER,
+ ALERTING
+ );
+
+ mSectionsManager.updateSectionBoundaries();
+
+ verifyMockStack(
+ ChildType.INCOMING_HEADER,
+ ChildType.HEADS_UP,
+ ChildType.HEADS_UP,
+ ChildType.HEADS_UP,
+ ChildType.PEOPLE_HEADER,
+ ChildType.PERSON,
+ ChildType.ALERTING_HEADER,
+ ChildType.ALERTING
+ );
+ }
+
private void enablePeopleFiltering() {
when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
}
@@ -657,7 +721,13 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
final List<View> children = new ArrayList<>();
when(mNssl.getChildCount()).thenAnswer(invocation -> children.size());
when(mNssl.getChildAt(anyInt()))
- .thenAnswer(invocation -> children.get(invocation.getArgument(0)));
+ .thenAnswer(invocation -> {
+ Integer index = invocation.getArgument(0);
+ if (index == null || index < 0 || index >= children.size()) {
+ return null;
+ }
+ return children.get(index);
+ });
when(mNssl.indexOfChild(any()))
.thenAnswer(invocation -> children.indexOf(invocation.getArgument(0)));
doAnswer(invocation -> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 31779cdf9e71..05cdd802167a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -16,34 +16,18 @@
package com.android.systemui.statusbar.phone;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.isNotNull;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.ContextWrapper;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
-import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableContentResolver;
-import android.testing.TestableContext;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -54,18 +38,14 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.SecureSetting;
-import com.android.systemui.statusbar.phone.AutoTileManagerTest.MyContextWrapper;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -84,18 +64,9 @@ public class AutoTileManagerTest extends SysuiTestCase {
private static final String TEST_CUSTOM_SPEC = "custom(" + TEST_COMPONENT + ")";
private static final String SEPARATOR = AutoTileManager.SETTING_SEPARATOR;
- private static final int USER = 0;
-
@Mock private QSTileHost mQsTileHost;
@Mock private AutoAddTracker mAutoAddTracker;
@Mock private CastController mCastController;
- @Mock private HotspotController mHotspotController;
- @Mock private DataSaverController mDataSaverController;
- @Mock private ManagedProfileController mManagedProfileController;
- @Mock private NightDisplayListener mNightDisplayListener;
- @Mock(answer = Answers.RETURNS_SELF)
- private AutoAddTracker.Builder mAutoAddTrackerBuilder;
- @Mock private Context mUserContext;
private AutoTileManager mAutoTileManager;
@@ -111,110 +82,20 @@ public class AutoTileManagerTest extends SysuiTestCase {
}
);
- when(mAutoAddTrackerBuilder.build()).thenReturn(mAutoAddTracker);
- when(mQsTileHost.getUserContext()).thenReturn(mUserContext);
- when(mUserContext.getUser()).thenReturn(UserHandle.of(USER));
-
- mAutoTileManager = createAutoTileManager(new
- MyContextWrapper(mContext));
+ mAutoTileManager = createAutoTileManager();
}
- @After
- public void tearDown() {
- mAutoTileManager.destroy();
- }
-
- private AutoTileManager createAutoTileManager(Context context) {
- return new AutoTileManager(context, mAutoAddTrackerBuilder, mQsTileHost,
+ private AutoTileManager createAutoTileManager() {
+ return new AutoTileManager(mContext, mAutoAddTracker, mQsTileHost,
Handler.createAsync(TestableLooper.get(this).getLooper()),
- mHotspotController,
- mDataSaverController,
- mManagedProfileController,
- mNightDisplayListener,
+ mock(HotspotController.class),
+ mock(DataSaverController.class),
+ mock(ManagedProfileController.class),
+ mock(NightDisplayListener.class),
mCastController);
}
@Test
- public void testChangeUserCallbacksStoppedAndStarted() throws Exception {
- TestableLooper.get(this).runWithLooper(() ->
- mAutoTileManager.changeUser(UserHandle.of(USER + 1))
- );
-
- InOrder inOrderHotspot = inOrder(mHotspotController);
- inOrderHotspot.verify(mHotspotController).removeCallback(any());
- inOrderHotspot.verify(mHotspotController).addCallback(any());
-
- InOrder inOrderDataSaver = inOrder(mDataSaverController);
- inOrderDataSaver.verify(mDataSaverController).removeCallback(any());
- inOrderDataSaver.verify(mDataSaverController).addCallback(any());
-
- InOrder inOrderManagedProfile = inOrder(mManagedProfileController);
- inOrderManagedProfile.verify(mManagedProfileController).removeCallback(any());
- inOrderManagedProfile.verify(mManagedProfileController).addCallback(any());
-
- InOrder inOrderNightDisplay = inOrder(mNightDisplayListener);
- inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNull());
- inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNotNull());
-
- InOrder inOrderCast = inOrder(mCastController);
- inOrderCast.verify(mCastController).removeCallback(any());
- inOrderCast.verify(mCastController).addCallback(any());
-
- SecureSetting setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
- assertEquals(USER + 1, setting.getCurrentUser());
- assertTrue(setting.isListening());
- }
-
- @Test
- public void testChangeUserSomeCallbacksNotAdded() throws Exception {
- when(mAutoAddTracker.isAdded("hotspot")).thenReturn(true);
- when(mAutoAddTracker.isAdded("work")).thenReturn(true);
- when(mAutoAddTracker.isAdded("cast")).thenReturn(true);
- when(mAutoAddTracker.isAdded(TEST_SPEC)).thenReturn(true);
-
- TestableLooper.get(this).runWithLooper(() ->
- mAutoTileManager.changeUser(UserHandle.of(USER + 1))
- );
-
- verify(mAutoAddTracker).changeUser(UserHandle.of(USER + 1));
-
- InOrder inOrderHotspot = inOrder(mHotspotController);
- inOrderHotspot.verify(mHotspotController).removeCallback(any());
- inOrderHotspot.verify(mHotspotController, never()).addCallback(any());
-
- InOrder inOrderDataSaver = inOrder(mDataSaverController);
- inOrderDataSaver.verify(mDataSaverController).removeCallback(any());
- inOrderDataSaver.verify(mDataSaverController).addCallback(any());
-
- InOrder inOrderManagedProfile = inOrder(mManagedProfileController);
- inOrderManagedProfile.verify(mManagedProfileController).removeCallback(any());
- inOrderManagedProfile.verify(mManagedProfileController, never()).addCallback(any());
-
- InOrder inOrderNightDisplay = inOrder(mNightDisplayListener);
- inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNull());
- inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNotNull());
-
- InOrder inOrderCast = inOrder(mCastController);
- inOrderCast.verify(mCastController).removeCallback(any());
- inOrderCast.verify(mCastController, never()).addCallback(any());
-
- SecureSetting setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
- assertEquals(USER + 1, setting.getCurrentUser());
- assertFalse(setting.isListening());
- }
-
- @Test
- public void testGetCurrentUserId() throws Exception {
- assertEquals(USER, mAutoTileManager.getCurrentUserId());
-
- TestableLooper.get(this).runWithLooper(() ->
- mAutoTileManager.changeUser(UserHandle.of(USER + 100))
- );
-
- assertEquals(USER + 100, mAutoTileManager.getCurrentUserId());
- }
-
- @Test
public void nightTileAdded_whenActivated() {
if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
return;
@@ -332,14 +213,14 @@ public class AutoTileManagerTest extends SysuiTestCase {
public void testEmptyArray_doesNotCrash() {
mContext.getOrCreateTestableResources().addOverride(
R.array.config_quickSettingsAutoAdd, new String[0]);
- createAutoTileManager(mContext).destroy();
+ createAutoTileManager();
}
@Test
public void testMissingConfig_doesNotCrash() {
mContext.getOrCreateTestableResources().addOverride(
R.array.config_quickSettingsAutoAdd, null);
- createAutoTileManager(mContext).destroy();
+ createAutoTileManager();
}
// Will only notify if it's listening
@@ -350,22 +231,4 @@ public class AutoTileManagerTest extends SysuiTestCase {
s.onChange(false);
}
}
-
- class MyContextWrapper extends ContextWrapper {
-
- private TestableContentResolver mSpiedTCR;
-
- MyContextWrapper(TestableContext context) {
- super(context);
- mSpiedTCR = spy(context.getContentResolver());
- doNothing().when(mSpiedTCR).registerContentObserver(any(), anyBoolean(), any(),
- anyInt());
- doNothing().when(mSpiedTCR).unregisterContentObserver(any());
- }
-
- @Override
- public ContentResolver getContentResolver() {
- return mSpiedTCR;
- }
- }
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 6ccdf245b271..961dc159009c 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -22,10 +22,14 @@ import static com.android.internal.util.FunctionalUtils.uncheckExceptions;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
+import static java.util.concurrent.TimeUnit.MINUTES;
+
import android.annotation.CheckResult;
import android.annotation.Nullable;
+import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.companion.Association;
import android.companion.AssociationRequest;
@@ -36,6 +40,7 @@ import android.companion.IFindDeviceCallback;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
@@ -55,6 +60,7 @@ import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.UserHandle;
+import android.os.UserManagerInternal;
import android.provider.Settings;
import android.provider.SettingsStringUtil.ComponentNameSet;
import android.text.BidiFormatter;
@@ -71,6 +77,7 @@ import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.PerUser;
import com.android.internal.infra.ServiceConnector;
import com.android.internal.notification.NotificationAccessConfirmationActivityContract;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -112,6 +119,9 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
private static final boolean DEBUG = false;
private static final String LOG_TAG = "CompanionDeviceManagerService";
+ private static final String PREF_FILE_NAME = "companion_device_preferences.xml";
+ private static final String PREF_KEY_AUTO_REVOKE_GRANTS_DONE = "auto_revoke_grants_done";
+
private static final String XML_TAG_ASSOCIATIONS = "associations";
private static final String XML_TAG_ASSOCIATION = "association";
private static final String XML_ATTR_PACKAGE = "package";
@@ -150,7 +160,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
};
-
registerPackageMonitor();
}
@@ -195,6 +204,36 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
if (atmInternal != null) {
atmInternal.setCompanionAppPackages(userHandle, companionAppPackages);
}
+
+ BackgroundThread.getHandler().sendMessageDelayed(
+ obtainMessage(CompanionDeviceManagerService::maybeGrantAutoRevokeExemptions, this),
+ MINUTES.toMillis(10));
+ }
+
+ void maybeGrantAutoRevokeExemptions() {
+ PackageManager pm = getContext().getPackageManager();
+ for (int userId : LocalServices.getService(UserManagerInternal.class).getUserIds()) {
+ SharedPreferences pref = getContext().getSharedPreferences(
+ new File(Environment.getUserSystemDirectory(userId), PREF_FILE_NAME),
+ Context.MODE_PRIVATE);
+ if (pref.getBoolean(PREF_KEY_AUTO_REVOKE_GRANTS_DONE, false)) {
+ continue;
+ }
+
+ try {
+ Set<Association> associations = readAllAssociations(userId);
+ for (Association a : associations) {
+ try {
+ int uid = pm.getPackageUidAsUser(a.companionAppPackage, userId);
+ exemptFromAutoRevoke(a.companionAppPackage, uid);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(LOG_TAG, "Unknown companion package: " + a.companionAppPackage, e);
+ }
+ }
+ } finally {
+ pref.edit().putBoolean(PREF_KEY_AUTO_REVOKE_GRANTS_DONE, true).apply();
+ }
+ }
}
@Override
@@ -469,6 +508,21 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
packageInfo.applicationInfo.uid,
NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
}
+
+ exemptFromAutoRevoke(packageInfo.packageName, packageInfo.applicationInfo.uid);
+ }
+
+ private void exemptFromAutoRevoke(String packageName, int uid) {
+ try {
+ mAppOpsManager.setMode(
+ AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
+ uid,
+ packageName,
+ AppOpsManager.MODE_IGNORED);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG,
+ "Error while granting auto revoke exemption for " + packageName, e);
+ }
}
private static <T> boolean containsEither(T[] array, T a, T b) {
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 35936babf3cb..be080e5cce62 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -233,7 +233,7 @@ final class UiModeManagerService extends SystemService {
public void onTwilightStateChanged(@Nullable TwilightState state) {
synchronized (mLock) {
if (mNightMode == UiModeManager.MODE_NIGHT_AUTO && mSystemReady) {
- if (mCar) {
+ if (shouldApplyAutomaticChangesImmediately()) {
updateLocked(0, 0);
} else {
registerScreenOffEventLocked();
@@ -1155,7 +1155,6 @@ final class UiModeManagerService extends SystemService {
void updateLocked(int enableFlags, int disableFlags) {
String action = null;
String oldAction = null;
- boolean originalComputedNightMode = mComputedNightMode;
if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
adjustStatusBarCarModeLocked();
oldAction = UiModeManager.ACTION_EXIT_CAR_MODE;
@@ -1236,16 +1235,11 @@ final class UiModeManagerService extends SystemService {
sendConfigurationAndStartDreamOrDockAppLocked(category);
}
- // reset overrides if mComputedNightMode changes
- if (originalComputedNightMode != mComputedNightMode) {
- resetNightModeOverrideLocked();
- }
-
// keep screen on when charging and in car mode
boolean keepScreenOn = mCharging &&
((mCarModeEnabled && mCarModeKeepsScreenOn &&
- (mCarModeEnableFlags & UiModeManager.ENABLE_CAR_MODE_ALLOW_SLEEP) == 0) ||
- (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn));
+ (mCarModeEnableFlags & UiModeManager.ENABLE_CAR_MODE_ALLOW_SLEEP) == 0) ||
+ (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn));
if (keepScreenOn != mWakeLock.isHeld()) {
if (keepScreenOn) {
mWakeLock.acquire();
@@ -1403,6 +1397,7 @@ final class UiModeManagerService extends SystemService {
mComputedNightMode = false;
return;
}
+ resetNightModeOverrideLocked();
}
private boolean resetNightModeOverrideLocked() {
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 2129e9bd34f3..6c415ca326c6 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1347,13 +1347,14 @@ public final class MultiClientInputMethodManagerService {
for (WindowInfo windowInfo : clientInfo.mWindowMap.values()) {
if (windowInfo.mWindowHandle == targetWindowHandle) {
final IBinder targetWindowToken = windowInfo.mWindowToken;
- // TODO(yukawa): Report targetWindowToken and targetWindowToken to WMS.
if (DEBUG) {
Slog.v(TAG, "reportImeWindowTarget"
+ " clientId=" + clientId
+ " imeWindowToken=" + imeWindowToken
+ " targetWindowToken=" + targetWindowToken);
}
+ mIWindowManagerInternal.updateInputMethodTargetWindow(
+ imeWindowToken, targetWindowToken);
}
}
// not found.
@@ -1490,6 +1491,9 @@ public final class MultiClientInputMethodManagerService {
case InputMethodClientState.ALREADY_SENT_BIND_RESULT:
try {
clientInfo.mMSInputMethodSession.showSoftInput(flags, resultReceiver);
+
+ // Forcing WM to show IME on imeTargetWindow
+ mWindowManagerInternal.showImePostLayout(token);
} catch (RemoteException e) {
}
break;
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 9a2aee3d8df6..93a27f2d17a9 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -598,6 +598,10 @@ class MediaRouter2ServiceImpl {
UserRecord userRecord = routerRecord.mUserRecord;
userRecord.mRouterRecords.remove(routerRecord);
+ routerRecord.mUserRecord.mHandler.sendMessage(
+ obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
+ routerRecord.mUserRecord.mHandler,
+ routerRecord.mPackageName, /* preferredFeatures=*/ null));
userRecord.mHandler.sendMessage(
obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
userRecord.mHandler));
@@ -613,7 +617,9 @@ class MediaRouter2ServiceImpl {
routerRecord.mDiscoveryPreference = discoveryRequest;
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
- routerRecord.mUserRecord.mHandler, routerRecord));
+ routerRecord.mUserRecord.mHandler,
+ routerRecord.mPackageName,
+ routerRecord.mDiscoveryPreference.getPreferredFeatures()));
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
routerRecord.mUserRecord.mHandler));
@@ -1954,7 +1960,8 @@ class MediaRouter2ServiceImpl {
}
}
- private void notifyPreferredFeaturesChangedToManagers(@NonNull RouterRecord routerRecord) {
+ private void notifyPreferredFeaturesChangedToManagers(@NonNull String routerPackageName,
+ @Nullable List<String> preferredFeatures) {
MediaRouter2ServiceImpl service = mServiceRef.get();
if (service == null) {
return;
@@ -1967,8 +1974,7 @@ class MediaRouter2ServiceImpl {
}
for (IMediaRouter2Manager manager : managers) {
try {
- manager.notifyPreferredFeaturesChanged(routerRecord.mPackageName,
- routerRecord.mDiscoveryPreference.getPreferredFeatures());
+ manager.notifyPreferredFeaturesChanged(routerPackageName, preferredFeatures);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify preferred features changed."
+ " Manager probably died.", ex);
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index 3829b6580c59..cfcf6ebf9540 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -21,6 +21,7 @@ import android.content.ContentUris;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.provider.CalendarContract.Attendees;
import android.provider.CalendarContract.Calendars;
@@ -102,6 +103,8 @@ public class CalendarTracker {
while (cursor != null && cursor.moveToNext()) {
rt.add(cursor.getLong(0));
}
+ } catch (SQLiteException e) {
+ Slog.w(TAG, "error querying calendar content provider", e);
} finally {
if (cursor != null) {
cursor.close();
@@ -118,11 +121,12 @@ public class CalendarTracker {
ContentUris.appendId(uriBuilder, time);
ContentUris.appendId(uriBuilder, time + EVENT_CHECK_LOOKAHEAD);
final Uri uri = uriBuilder.build();
- final Cursor cursor = mUserContext.getContentResolver().query(uri, INSTANCE_PROJECTION,
- null, null, INSTANCE_ORDER_BY);
+ Cursor cursor = null;
final CheckEventResult result = new CheckEventResult();
result.recheckAt = time + EVENT_CHECK_LOOKAHEAD;
try {
+ cursor = mUserContext.getContentResolver().query(uri, INSTANCE_PROJECTION,
+ null, null, INSTANCE_ORDER_BY);
final ArraySet<Long> calendars = getCalendarsWithAccess();
while (cursor != null && cursor.moveToNext()) {
final long begin = cursor.getLong(0);
@@ -183,9 +187,10 @@ public class CalendarTracker {
selection = null;
selectionArgs = null;
}
- final Cursor cursor = mUserContext.getContentResolver().query(Attendees.CONTENT_URI,
- ATTENDEE_PROJECTION, selection, selectionArgs, null);
+ Cursor cursor = null;
try {
+ cursor = mUserContext.getContentResolver().query(Attendees.CONTENT_URI,
+ ATTENDEE_PROJECTION, selection, selectionArgs, null);
if (cursor == null || cursor.getCount() == 0) {
if (DEBUG) Log.d(TAG, "No attendees found");
return true;
@@ -205,6 +210,9 @@ public class CalendarTracker {
rt |= eventMeets;
}
return rt;
+ } catch (SQLiteException e) {
+ Slog.w(TAG, "error querying attendees content provider", e);
+ return false;
} finally {
if (cursor != null) {
cursor.close();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 7ab05c4f762c..de8ad6b7db13 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2108,6 +2108,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
baseApk = apk;
}
+ // Validate and add Dex Metadata (.dm).
final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
if (dexMetadataFile != null) {
if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
@@ -2295,6 +2296,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
"Missing split for " + mPackageName);
}
+
+ final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID);
+ if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) {
+ if (!baseApk.debuggable && !baseApk.profilableByShell) {
+ mIncrementalFileStorages.disableReadLogs();
+ }
+ }
}
private void resolveAndStageFile(File origFile, File targetFile)
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 8ccf837f64dc..515225b1d3be 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -53,6 +53,7 @@ import android.os.ParcelableException;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.os.storage.IStorageManager;
@@ -1155,6 +1156,11 @@ public class StagingManager {
}
private void checkStateAndResume(@NonNull PackageInstallerSession session) {
+ // Do not resume session if boot completed already
+ if (SystemProperties.getBoolean("sys.boot_completed", false)) {
+ return;
+ }
+
if (!session.isCommitted()) {
// Session hasn't been committed yet, ignore.
return;
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 41aa4ee65f30..7cb59dcbfb9b 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
+import android.media.IResourceManagerService;
import android.media.tv.TvInputManager;
import android.media.tv.tunerresourcemanager.CasSessionRequest;
import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
@@ -53,7 +54,7 @@ import java.util.Set;
*
* @hide
*/
-public class TunerResourceManagerService extends SystemService {
+public class TunerResourceManagerService extends SystemService implements IBinder.DeathRecipient {
private static final String TAG = "TunerResourceManagerService";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -76,6 +77,7 @@ public class TunerResourceManagerService extends SystemService {
private TvInputManager mTvInputManager;
private ActivityManager mActivityManager;
+ private IResourceManagerService mMediaResourceManager;
private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints();
// An internal resource request count to help generate resource handle.
@@ -102,6 +104,22 @@ public class TunerResourceManagerService extends SystemService {
mActivityManager =
(ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
mPriorityCongfig.parse();
+
+ if (mMediaResourceManager == null) {
+ IBinder mediaResourceManagerBinder = getBinderService("media.resource_manager");
+ if (mediaResourceManagerBinder == null) {
+ Slog.w(TAG, "Resource Manager Service not available.");
+ return;
+ }
+ try {
+ mediaResourceManagerBinder.linkToDeath(this, /*flags*/ 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not link to death of native resource manager service.");
+ return;
+ }
+ mMediaResourceManager = IResourceManagerService.Stub.asInterface(
+ mediaResourceManagerBinder);
+ }
}
private final class BinderService extends ITunerResourceManager.Stub {
@@ -380,6 +398,19 @@ public class TunerResourceManagerService extends SystemService {
}
}
+ /**
+ * Handle the death of the native resource manager service
+ */
+ @Override
+ public void binderDied() {
+ if (DEBUG) {
+ Slog.w(TAG, "Native media resource manager service has died");
+ }
+ synchronized (mLock) {
+ mMediaResourceManager = null;
+ }
+ }
+
@VisibleForTesting
protected void registerClientProfileInternal(ResourceClientProfile profile,
IResourcesReclaimListener listener, int[] clientId) {
@@ -399,6 +430,16 @@ public class TunerResourceManagerService extends SystemService {
? Binder.getCallingPid() /*callingPid*/
: mTvInputManager.getClientPid(profile.getTvInputSessionId()); /*tvAppId*/
+ // Update Media Resource Manager with the tvAppId
+ if (profile.getTvInputSessionId() != null && mMediaResourceManager != null) {
+ try {
+ mMediaResourceManager.overridePid(Binder.getCallingPid(), pid);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not overridePid in resourceManagerSercice,"
+ + " remote exception: " + e);
+ }
+ }
+
ClientProfile clientProfile = new ClientProfile.Builder(clientId[0])
.tvInputSessionId(profile.getTvInputSessionId())
.useCase(profile.getUseCase())
@@ -415,6 +456,15 @@ public class TunerResourceManagerService extends SystemService {
Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")");
}
removeClientProfile(clientId);
+ // Remove the Media Resource Manager callingPid to tvAppId mapping
+ if (mMediaResourceManager != null) {
+ try {
+ mMediaResourceManager.overridePid(Binder.getCallingPid(), -1);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not overridePid in resourceManagerSercice when unregister,"
+ + " remote exception: " + e);
+ }
+ }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 01eb9c5cb3d9..597fa949f4bf 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3355,6 +3355,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final long origId = Binder.clearCallingIdentity();
try {
+ // Link the fixed rotation transform to this activity since we are transferring the
+ // starting window.
+ if (fromActivity.hasFixedRotationTransform()) {
+ mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this,
+ false /* checkOpening */);
+ }
+
// Transfer the starting window over to the new token.
mStartingData = fromActivity.mStartingData;
startingSurface = fromActivity.startingSurface;
@@ -7717,24 +7724,25 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
outAppBounds.set(outBounds);
}
} else {
- outBounds.set(0, 0, mWidth, mHeight);
- getFrameByOrientation(outAppBounds, orientation);
- if (orientationRequested && !canChangeOrientation
- && (outAppBounds.width() > outAppBounds.height()) != (mWidth > mHeight)) {
- // The orientation is mismatched but the display cannot rotate. The bounds will
- // fit to the short side of display.
- if (orientation == ORIENTATION_LANDSCAPE) {
- outAppBounds.bottom = (int) ((float) mWidth * mWidth / mHeight);
- outAppBounds.right = mWidth;
- } else {
- outAppBounds.bottom = mHeight;
- outAppBounds.right = (int) ((float) mHeight * mHeight / mWidth);
+ if (orientationRequested) {
+ getFrameByOrientation(outBounds, orientation);
+ if ((outBounds.width() > outBounds.height()) != (mWidth > mHeight)) {
+ // The orientation is mismatched but the display cannot rotate. The bounds
+ // will fit to the short side of display.
+ if (orientation == ORIENTATION_LANDSCAPE) {
+ outBounds.bottom = (int) ((float) mWidth * mWidth / mHeight);
+ outBounds.right = mWidth;
+ } else {
+ outBounds.bottom = mHeight;
+ outBounds.right = (int) ((float) mHeight * mHeight / mWidth);
+ }
+ outBounds.offset(
+ getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
}
- outAppBounds.offset(getHorizontalCenterOffset(outBounds.width(),
- outAppBounds.width()), 0 /* dy */);
} else {
- outAppBounds.set(outBounds);
+ outBounds.set(0, 0, mWidth, mHeight);
}
+ outAppBounds.set(outBounds);
}
if (rotation != ROTATION_UNDEFINED) {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 4bede4c3623f..b4bc0f5b3a32 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -813,7 +813,7 @@ class ActivityStack extends Task {
/** Resume next focusable stack after reparenting to another display. */
void postReparent() {
adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */,
- true /* moveParentsToTop */);
+ true /* moveDisplayToTop */);
mRootWindowContainer.resumeFocusedStacksTopActivities();
// Update visibility of activities before notifying WM. This way it won't try to resize
// windows that are no longer visible.
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 8b14095874e3..26e0790a7604 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -59,6 +59,7 @@ public class BarController {
private final int mTransparentFlag;
private final int mStatusBarManagerId;
private final int mTranslucentWmFlag;
+ private final int mWindowType;
protected final Handler mHandler;
private final Object mServiceAquireLock = new Object();
private StatusBarManagerInternal mStatusBarInternal;
@@ -77,13 +78,14 @@ public class BarController {
private OnBarVisibilityChangedListener mVisibilityChangeListener;
BarController(String tag, int displayId, int transientFlag, int unhideFlag, int translucentFlag,
- int statusBarManagerId, int translucentWmFlag, int transparentFlag) {
+ int statusBarManagerId, int windowType, int translucentWmFlag, int transparentFlag) {
mTag = "BarController." + tag;
mDisplayId = displayId;
mTransientFlag = transientFlag;
mUnhideFlag = unhideFlag;
mTranslucentFlag = translucentFlag;
mStatusBarManagerId = statusBarManagerId;
+ mWindowType = windowType;
mTranslucentWmFlag = translucentWmFlag;
mTransparentFlag = transparentFlag;
mHandler = new BarHandler();
@@ -168,7 +170,12 @@ public class BarController {
}
boolean isTransparentAllowed(WindowState win) {
- return win == null || win.letterboxNotIntersectsOrFullyContains(mContentFrame);
+ if (win == null) {
+ return true;
+ }
+ final Rect rotatedContentFrame = win.mToken.getFixedRotationBarContentFrame(mWindowType);
+ final Rect contentFrame = rotatedContentFrame != null ? rotatedContentFrame : mContentFrame;
+ return win.letterboxNotIntersectsOrFullyContains(contentFrame);
}
boolean setBarShowingLw(final boolean show) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4e19a5224bb4..fb602573e31b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5647,8 +5647,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
if (animatingRecents != null && animatingRecents == mFixedRotationLaunchingApp) {
- // Because it won't affect display orientation, just finish the transform.
- animatingRecents.finishFixedRotationTransform();
+ // The recents activity should be going to be invisible (switch to another app or
+ // return to original top). Only clear the top launching record without finishing
+ // the transform immediately because it won't affect display orientation. And before
+ // the visibility is committed, the recents activity may perform relayout which may
+ // cause unexpected configuration change if the rotated configuration is restored.
+ // The transform will be finished when the transition is done.
setFixedRotationLaunchingAppUnchecked(null);
} else {
// If there is already a launching activity that is not the recents, before its
@@ -5671,7 +5675,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
if (mFixedRotationLaunchingApp != null
&& mFixedRotationLaunchingApp.hasFixedRotationTransform(r)) {
- continueUpdateOrientationForDiffOrienLaunchingApp();
+ // Waiting until all of the associated activities have done animation, or the
+ // orientation would be updated too early and cause flickers.
+ if (!mFixedRotationLaunchingApp.hasAnimatingFixedRotationTransition()) {
+ continueUpdateOrientationForDiffOrienLaunchingApp();
+ }
} else {
r.finishFixedRotationTransform();
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e244b5551d19..3c4a9ad08199 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -151,6 +151,7 @@ import android.util.IntArray;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.InputChannel;
@@ -199,6 +200,7 @@ import com.android.server.wallpaper.WallpaperManagerInternal;
import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* The policy that provides the basic behaviors and states of a display to show UI.
@@ -471,6 +473,7 @@ public class DisplayPolicy {
View.NAVIGATION_BAR_UNHIDE,
View.NAVIGATION_BAR_TRANSLUCENT,
StatusBarManager.WINDOW_NAVIGATION_BAR,
+ TYPE_NAVIGATION_BAR,
FLAG_TRANSLUCENT_NAVIGATION,
View.NAVIGATION_BAR_TRANSPARENT);
@@ -1171,6 +1174,11 @@ public class DisplayPolicy {
displayFrames.mDisplayCutoutSafe.top);
}
+ @VisibleForTesting
+ StatusBarController getStatusBarController() {
+ return mStatusBarController;
+ }
+
WindowState getStatusBar() {
return mStatusBar;
}
@@ -1469,13 +1477,16 @@ public class DisplayPolicy {
}
private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames,
- InsetsState insetsState, WindowFrames simulatedWindowFrames, Runnable layout) {
+ InsetsState insetsState, WindowFrames simulatedWindowFrames,
+ SparseArray<Rect> contentFrames, Consumer<Rect> layout) {
win.setSimulatedWindowFrames(simulatedWindowFrames);
+ final Rect contentFrame = new Rect();
try {
- layout.run();
+ layout.accept(contentFrame);
} finally {
win.setSimulatedWindowFrames(null);
}
+ contentFrames.put(win.mAttrs.type, contentFrame);
mDisplayContent.getInsetsStateController().computeSimulatedState(insetsState, win,
displayFrames, simulatedWindowFrames);
}
@@ -1487,24 +1498,25 @@ public class DisplayPolicy {
* state and some temporal states. In other words, it doesn't change the window frames used to
* show on screen.
*/
- void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState, int uiMode) {
+ void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState,
+ SparseArray<Rect> barContentFrames) {
displayFrames.onBeginLayout();
updateInsetsStateForDisplayCutout(displayFrames, insetsState);
insetsState.setDisplayFrame(displayFrames.mUnrestricted);
final WindowFrames simulatedWindowFrames = new WindowFrames();
if (mNavigationBar != null) {
- simulateLayoutDecorWindow(
- mNavigationBar, displayFrames, insetsState, simulatedWindowFrames,
- () -> layoutNavigationBar(displayFrames, uiMode, mLastNavVisible,
+ simulateLayoutDecorWindow(mNavigationBar, displayFrames, insetsState,
+ simulatedWindowFrames, barContentFrames,
+ contentFrame -> layoutNavigationBar(displayFrames,
+ mDisplayContent.getConfiguration().uiMode, mLastNavVisible,
mLastNavTranslucent, mLastNavAllowedHidden,
- mLastNotificationShadeForcesShowingNavigation,
- false /* isRealLayout */));
+ mLastNotificationShadeForcesShowingNavigation, contentFrame));
}
if (mStatusBar != null) {
- simulateLayoutDecorWindow(
- mStatusBar, displayFrames, insetsState, simulatedWindowFrames,
- () -> layoutStatusBar(displayFrames, mLastSystemUiFlags,
- false /* isRealLayout */));
+ simulateLayoutDecorWindow(mStatusBar, displayFrames, insetsState,
+ simulatedWindowFrames, barContentFrames,
+ contentFrame -> layoutStatusBar(displayFrames, mLastSystemUiFlags,
+ contentFrame));
}
layoutScreenDecorWindows(displayFrames, simulatedWindowFrames);
postAdjustDisplayFrames(displayFrames);
@@ -1556,9 +1568,10 @@ public class DisplayPolicy {
boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation,
- true /* isRealLayout */);
+ null /* simulatedContentFrame */);
if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
- updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, true /* isRealLayout */);
+ updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui,
+ null /* simulatedContentFrame */);
if (updateSysUiVisibility) {
updateSystemUiVisibilityLw();
}
@@ -1579,10 +1592,9 @@ public class DisplayPolicy {
navControlTarget instanceof WindowState ? (WindowState) navControlTarget : null;
final InsetsState requestedState = navControllingWin != null
? navControllingWin.getRequestedInsetsState() : null;
- final InsetsSource navSource = requestedState != null
- ? requestedState.peekSource(ITYPE_NAVIGATION_BAR) : null;
- final boolean navVisible = navSource != null
- ? navSource.isVisible() : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
+ final boolean navVisible = requestedState != null
+ ? requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)
+ : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
final boolean showBarsByTouch = navControllingWin != null
&& navControllingWin.mAttrs.insetsFlags.behavior == BEHAVIOR_SHOW_BARS_BY_TOUCH;
// When the navigation bar isn't visible, we put up a fake input window to catch all
@@ -1731,7 +1743,8 @@ public class DisplayPolicy {
displayFrames.mContent.set(dockFrame);
}
- private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui, boolean isRealLayout) {
+ private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
+ Rect simulatedContentFrame) {
// decide where the status bar goes ahead of time
if (mStatusBar == null) {
return false;
@@ -1754,12 +1767,14 @@ public class DisplayPolicy {
displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
displayFrames.mDisplayCutoutSafe.top);
- if (isRealLayout) {
- // Tell the bar controller where the collapsed status bar content is.
- sTmpRect.set(windowFrames.mContentFrame);
- sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
- sTmpRect.top = windowFrames.mContentFrame.top; // Ignore top display cutout inset
- sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
+ // Tell the bar controller where the collapsed status bar content is.
+ sTmpRect.set(windowFrames.mContentFrame);
+ sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
+ sTmpRect.top = windowFrames.mContentFrame.top; // Ignore top display cutout inset
+ sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
+ if (simulatedContentFrame != null) {
+ simulatedContentFrame.set(sTmpRect);
+ } else {
mStatusBarController.setContentFrame(sTmpRect);
}
@@ -1796,7 +1811,7 @@ public class DisplayPolicy {
private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
boolean navTranslucent, boolean navAllowedHidden,
- boolean statusBarForcesShowingNavigation, boolean isRealLayout) {
+ boolean statusBarForcesShowingNavigation, Rect simulatedContentFrame) {
if (mNavigationBar == null) {
return false;
}
@@ -1900,7 +1915,9 @@ public class DisplayPolicy {
navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
navigationFrame /* stableFrame */);
mNavigationBar.computeFrame(displayFrames);
- if (isRealLayout) {
+ if (simulatedContentFrame != null) {
+ simulatedContentFrame.set(windowFrames.mContentFrame);
+ } else {
mNavigationBarPosition = navBarPosition;
mNavigationBarController.setContentFrame(windowFrames.mContentFrame);
}
@@ -2372,12 +2389,13 @@ public class DisplayPolicy {
final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
|| (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
|| (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- && !win.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
+ && !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
+ ITYPE_STATUS_BAR));
final boolean requestedHideNavigation =
(requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
|| (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- && !win.getRequestedInsetsState().getSource(ITYPE_NAVIGATION_BAR)
- .isVisible());
+ && !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
+ ITYPE_NAVIGATION_BAR));
// TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
// cropped / shifted to the displayFrame in WindowState.
@@ -3187,24 +3205,32 @@ public class DisplayPolicy {
return;
}
if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- if (swipeTarget == mNavigationBar
- && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
- // Don't show status bar when swiping on already visible navigation bar
- return;
- }
final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
final InsetsControlTarget controlTarget = provider != null
? provider.getControlTarget() : null;
- // No transient mode on lockscreen (in notification shade window).
if (controlTarget == null || controlTarget == getNotificationShade()) {
+ // No transient mode on lockscreen (in notification shade window).
return;
}
+
+ if (swipeTarget == mNavigationBar
+ && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
+ // Don't show status bar when swiping on already visible navigation bar.
+ // But restore the position of navigation bar if it has been moved by the control
+ // target.
+ controlTarget.showInsets(Type.navigationBars(), false);
+ return;
+ }
+
+ int insetsTypesToShow = Type.systemBars();
+
if (controlTarget.canShowTransient()) {
- mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
+ insetsTypesToShow &= ~mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
- } else {
- controlTarget.showInsets(Type.systemBars(), false);
+ }
+ if (insetsTypesToShow != 0) {
+ controlTarget.showInsets(insetsTypesToShow, false);
}
} else {
boolean sb = mStatusBarController.checkShowTransientBarLw();
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 035f2015fe91..be6e4b76e8ed 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -42,6 +42,7 @@ import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.ViewRootImpl;
+import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.WindowInsetsAnimationControlListener;
@@ -127,14 +128,16 @@ class InsetsPolicy {
return provider != null && provider.hasWindow() && !provider.getSource().isVisible();
}
- void showTransient(IntArray types) {
+ @InsetsType int showTransient(IntArray types) {
+ @InsetsType int showingTransientTypes = 0;
boolean changed = false;
for (int i = types.size() - 1; i >= 0; i--) {
final int type = types.get(i);
- if (mShowingTransientTypes.indexOf(type) != -1) {
+ if (!isHidden(type)) {
continue;
}
- if (!isHidden(type)) {
+ showingTransientTypes |= InsetsState.toPublicType(type);
+ if (mShowingTransientTypes.indexOf(type) != -1) {
continue;
}
mShowingTransientTypes.add(type);
@@ -161,6 +164,7 @@ class InsetsPolicy {
}
});
}
+ return showingTransientTypes;
}
void hideTransient() {
@@ -192,18 +196,6 @@ class InsetsPolicy {
state = new InsetsState(state);
state.setSourceVisible(mShowingTransientTypes.get(i), false);
}
- if (mFocusedWin != null && getStatusControlTarget(mFocusedWin) == mDummyControlTarget) {
- if (state == originalState) {
- state = new InsetsState(state);
- }
- state.setSourceVisible(ITYPE_STATUS_BAR, mFocusedWin.getRequestedInsetsState());
- }
- if (mFocusedWin != null && getNavControlTarget(mFocusedWin) == mDummyControlTarget) {
- if (state == originalState) {
- state = new InsetsState(state);
- }
- state.setSourceVisible(ITYPE_NAVIGATION_BAR, mFocusedWin.getRequestedInsetsState());
- }
return state;
}
@@ -373,7 +365,7 @@ class InsetsPolicy {
final WindowState controllingWin =
controlTarget instanceof WindowState ? (WindowState) controlTarget : null;
setVisible(controllingWin == null
- || controllingWin.getRequestedInsetsState().getSource(type).isVisible());
+ || controllingWin.getRequestedInsetsState().getSourceOrDefaultVisibility(type));
}
private void setVisible(boolean visible) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index bded65141a3a..178082016bbb 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -233,6 +233,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// duration of the gesture that is driven by the recents component
targetActivity.mLaunchTaskBehind = true;
mLaunchedTargetActivity = targetActivity;
+ // TODO(b/156772625): Evaluate to send new intents vs. replacing the intent extras.
+ targetActivity.intent.replaceExtras(mTargetIntent);
// Fetch all the surface controls and pass them to the client to get the animation
// started. Cancel any existing recents animation running synchronously (do not hold the
diff --git a/services/core/java/com/android/server/wm/StatusBarController.java b/services/core/java/com/android/server/wm/StatusBarController.java
index cac992a67541..3564e0bce5f5 100644
--- a/services/core/java/com/android/server/wm/StatusBarController.java
+++ b/services/core/java/com/android/server/wm/StatusBarController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
@@ -90,6 +91,7 @@ public class StatusBarController extends BarController {
View.STATUS_BAR_UNHIDE,
View.STATUS_BAR_TRANSLUCENT,
StatusBarManager.WINDOW_STATUS_BAR,
+ TYPE_STATUS_BAR,
FLAG_TRANSLUCENT_STATUS,
View.STATUS_BAR_TRANSPARENT);
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 56ad9643e619..c749125ec531 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2638,7 +2638,7 @@ class Task extends WindowContainer<WindowContainer> {
*/
ActivityStack adjustFocusToNextFocusableTask(String reason) {
return adjustFocusToNextFocusableTask(reason, false /* allowFocusSelf */,
- true /* moveParentsToTop */);
+ true /* moveDisplayToTop */);
}
/** Return the next focusable task by looking from the siblings and parent tasks */
@@ -2661,11 +2661,11 @@ class Task extends WindowContainer<WindowContainer> {
* Find next proper focusable task and make it focused.
* @param reason The reason of making the adjustment.
* @param allowFocusSelf Is the focus allowed to remain on the same task.
- * @param moveParentsToTop Whether to move parents to top while making the task focused.
+ * @param moveDisplayToTop Whether to move display to top while making the task focused.
* @return The root task that now got the focus, {@code null} if none found.
*/
ActivityStack adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf,
- boolean moveParentsToTop) {
+ boolean moveDisplayToTop) {
ActivityStack focusableTask = (ActivityStack) getNextFocusableTask(allowFocusSelf);
if (focusableTask == null) {
focusableTask = mRootWindowContainer.getNextFocusableStack((ActivityStack) this,
@@ -2676,10 +2676,17 @@ class Task extends WindowContainer<WindowContainer> {
}
final ActivityStack rootTask = (ActivityStack) focusableTask.getRootTask();
- if (!moveParentsToTop) {
- // Only move the next stack to top in its task container.
+ if (!moveDisplayToTop) {
+ // There may be multiple task layers above this task, so when relocating the task to the
+ // top, we should move this task and each of its parent task that below display area to
+ // the top of each layer.
WindowContainer parent = focusableTask.getParent();
- parent.positionChildAt(POSITION_TOP, focusableTask, false /* includingParents */);
+ WindowContainer next = focusableTask;
+ do {
+ parent.positionChildAt(POSITION_TOP, next, false /* includingParents */);
+ next = parent;
+ parent = next.getParent();
+ } while (next.asTask() != null && parent != null);
return rootTask;
}
@@ -2917,7 +2924,12 @@ class Task extends WindowContainer<WindowContainer> {
}
boolean cropWindowsToStackBounds() {
- return isResizeable();
+ // Don't crop HOME/RECENTS windows to stack bounds. This is because in split-screen
+ // they extend past their stack and sysui uses the stack surface to control cropping.
+ // TODO(b/158242495): get rid of this when drag/drop can use surface bounds.
+ final boolean isTopHomeOrRecents = (isActivityTypeHome() || isActivityTypeRecents())
+ && getRootTask().getTopMostTask() == this;
+ return isResizeable() && !isTopHomeOrRecents;
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 102c2a6364f4..6b8800a8eb0a 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -207,6 +207,15 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
return mRootSplitScreenPrimaryTask;
}
+ ActivityStack getRootSplitScreenSecondaryTask() {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ if (mChildren.get(i).inSplitScreenSecondaryWindowingMode()) {
+ return mChildren.get(i);
+ }
+ }
+ return null;
+ }
+
ArrayList<Task> getVisibleTasks() {
final ArrayList<Task> visibleTasks = new ArrayList<>();
forAllTasks(task -> {
@@ -299,8 +308,17 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
@Override
void positionChildAt(int position, ActivityStack child, boolean includingParents) {
- final boolean moveToTop = (position == POSITION_TOP || position == getChildCount());
+ final boolean moveToTop = position >= getChildCount() - 1;
final boolean moveToBottom = (position == POSITION_BOTTOM || position == 0);
+
+ // Reset mPreferredTopFocusableStack before positioning to top or {@link
+ // ActivityStackSupervisor#updateTopResumedActivityIfNeeded()} won't update the top
+ // resumed activity.
+ final boolean wasContained = mChildren.contains(child);
+ if (moveToTop && wasContained && child.isFocusable()) {
+ mPreferredTopFocusableStack = null;
+ }
+
if (child.getWindowConfiguration().isAlwaysOnTop() && !moveToTop) {
// This stack is always-on-top, override the default behavior.
Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + this + " to bottom");
@@ -330,6 +348,17 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
child.updateTaskMovement(moveToTop);
mDisplayContent.setLayoutNeeded();
+
+ // The insert position may be adjusted to non-top when there is always-on-top stack. Since
+ // the original position is preferred to be top, the stack should have higher priority when
+ // we are looking for top focusable stack. The condition {@code wasContained} restricts the
+ // preferred stack is set only when moving an existing stack to top instead of adding a new
+ // stack that may be too early (e.g. in the middle of launching or reparenting).
+ if (moveToTop && child.isFocusableAndVisible()) {
+ mPreferredTopFocusableStack = child;
+ } else if (mPreferredTopFocusableStack == child) {
+ mPreferredTopFocusableStack = null;
+ }
}
/**
@@ -727,29 +756,10 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
"positionStackAt: Can only have one task on display=" + this);
}
- final boolean movingToTop = wasContained && position >= getStackCount() - 1;
- // Reset mPreferredTopFocusableStack before positioning to top or {@link
- // ActivityStackSupervisor#updateTopResumedActivityIfNeeded()} won't update the top
- // resumed activity.
- if (movingToTop && stack.isFocusable()) {
- mPreferredTopFocusableStack = null;
- }
-
// Since positionChildAt() is called during the creation process of pinned stacks,
// ActivityStack#getStack() can be null.
positionStackAt(position, stack, includingParents);
- // The insert position may be adjusted to non-top when there is always-on-top stack. Since
- // the original position is preferred to be top, the stack should have higher priority when
- // we are looking for top focusable stack. The condition {@code wasContained} restricts the
- // preferred stack is set only when moving an existing stack to top instead of adding a new
- // stack that may be too early (e.g. in the middle of launching or reparenting).
- if (movingToTop && stack.isFocusableAndVisible()) {
- mPreferredTopFocusableStack = stack;
- } else if (mPreferredTopFocusableStack == stack) {
- mPreferredTopFocusableStack = null;
- }
-
if (updateLastFocusedStackReason != null) {
final ActivityStack currentFocusedStack = getFocusedStack();
if (currentFocusedStack != prevFocusedStack) {
@@ -1741,21 +1751,23 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
// reparenting stack finished.
// Keep the order from bottom to top.
int numStacks = getStackCount();
+
+ final boolean splitScreenActivated = toDisplayArea.isSplitScreenModeActivated();
+ final ActivityStack rootStack = splitScreenActivated ? toDisplayArea
+ .getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null;
for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
final ActivityStack stack = getStackAt(stackNdx);
// Always finish non-standard type stacks.
if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
stack.finishAllActivitiesImmediately();
} else {
- // If default display is in split-window mode, set windowing mode of the
- // stack to split-screen secondary. Otherwise, set the windowing mode to
- // undefined by default to let stack inherited the windowing mode from the
- // new display.
- final int windowingMode = toDisplayArea.isSplitScreenModeActivated()
- ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
- : WINDOWING_MODE_UNDEFINED;
- stack.reparent(toDisplayArea, true /* onTop */);
- stack.setWindowingMode(windowingMode);
+ // Reparent the stack to the root task of secondary-split-screen or display area.
+ stack.reparent(stack.supportsSplitScreenWindowingMode() && rootStack != null
+ ? rootStack : toDisplayArea, POSITION_TOP);
+
+ // Set the windowing mode to undefined by default to let the stack inherited the
+ // windowing mode.
+ stack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
lastReparentedStack = stack;
}
// Stacks may be removed from this display. Ensure each stack will be processed
@@ -1763,6 +1775,17 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
stackNdx -= numStacks - getStackCount();
numStacks = getStackCount();
}
+ if (lastReparentedStack != null && splitScreenActivated) {
+ if (!lastReparentedStack.supportsSplitScreenWindowingMode()) {
+ mAtmService.getTaskChangeNotificationController()
+ .notifyActivityDismissingDockedStack();
+ toDisplayArea.onSplitScreenModeDismissed(lastReparentedStack);
+ } else if (rootStack != null) {
+ // update focus
+ rootStack.moveToFront("display-removed");
+ }
+ }
+
mRemoved = true;
return lastReparentedStack;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 32717d0e1e65..6bbc019ed5e7 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1529,6 +1529,29 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
/**
+ * This is a form of rectangle "difference". It cut off each dimension of rect by the amount
+ * that toRemove is "pushing into" it from the outside. Any dimension that fully contains
+ * toRemove won't change.
+ */
+ private void cutRect(Rect rect, Rect toRemove) {
+ if (toRemove.isEmpty()) return;
+ if (toRemove.top < rect.bottom && toRemove.bottom > rect.top) {
+ if (toRemove.right >= rect.right && toRemove.left >= rect.left) {
+ rect.right = toRemove.left;
+ } else if (toRemove.left <= rect.left && toRemove.right <= rect.right) {
+ rect.left = toRemove.right;
+ }
+ }
+ if (toRemove.left < rect.right && toRemove.right > rect.left) {
+ if (toRemove.bottom >= rect.bottom && toRemove.top >= rect.top) {
+ rect.bottom = toRemove.top;
+ } else if (toRemove.top <= rect.top && toRemove.bottom <= rect.bottom) {
+ rect.top = toRemove.bottom;
+ }
+ }
+ }
+
+ /**
* Retrieves the visible bounds of the window.
* @param bounds The rect which gets the bounds.
*/
@@ -1544,6 +1567,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
} else {
intersectWithStackBounds = false;
}
+ if (inSplitScreenPrimaryWindowingMode()) {
+ // If this is in the primary split and the home stack is the top visible task in
+ // the secondary split, it means this is "minimized" and thus must prevent
+ // overlapping with home.
+ // TODO(b/158242495): get rid of this when drag/drop can use surface bounds.
+ final ActivityStack rootSecondary =
+ task.getDisplayArea().getRootSplitScreenSecondaryTask();
+ if (rootSecondary.isActivityTypeHome() || rootSecondary.isActivityTypeRecents()) {
+ final WindowContainer topTask = rootSecondary.getTopChild();
+ if (topTask.isVisible()) {
+ cutRect(mTmpRect, topTask.getBounds());
+ }
+ }
+ }
}
bounds.set(mWindowFrames.mVisibleFrame);
@@ -3576,6 +3613,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
public void notifyInsetsControlChanged() {
ProtoLog.d(WM_DEBUG_IME, "notifyInsetsControlChanged for %s ", this);
+ if (mAppDied || mRemoved) {
+ return;
+ }
final InsetsStateController stateController =
getDisplayContent().getInsetsStateController();
try {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index d2570023f419..86aacf308068 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -48,6 +48,7 @@ import android.os.Debug;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.DisplayInfo;
@@ -124,7 +125,7 @@ class WindowToken extends WindowContainer<WindowState> {
private static class FixedRotationTransformState {
final DisplayInfo mDisplayInfo;
final DisplayFrames mDisplayFrames;
- final InsetsState mInsetsState;
+ final InsetsState mInsetsState = new InsetsState();
final Configuration mRotatedOverrideConfiguration;
final SeamlessRotator mRotator;
/**
@@ -133,14 +134,14 @@ class WindowToken extends WindowContainer<WindowState> {
*/
final ArrayList<WindowToken> mAssociatedTokens = new ArrayList<>(3);
final ArrayList<WindowContainer<?>> mRotatedContainers = new ArrayList<>(3);
+ final SparseArray<Rect> mBarContentFrames = new SparseArray<>();
boolean mIsTransforming = true;
FixedRotationTransformState(DisplayInfo rotatedDisplayInfo,
- DisplayFrames rotatedDisplayFrames, InsetsState rotatedInsetsState,
- Configuration rotatedConfig, int currentRotation) {
+ DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig,
+ int currentRotation) {
mDisplayInfo = rotatedDisplayInfo;
mDisplayFrames = rotatedDisplayFrames;
- mInsetsState = rotatedInsetsState;
mRotatedOverrideConfiguration = rotatedConfig;
// This will use unrotate as rotate, so the new and old rotation are inverted.
mRotator = new SeamlessRotator(rotatedDisplayInfo.rotation, currentRotation,
@@ -516,6 +517,12 @@ class WindowToken extends WindowContainer<WindowState> {
: null;
}
+ Rect getFixedRotationBarContentFrame(int windowType) {
+ return isFixedRotationTransforming()
+ ? mFixedRotationTransformState.mBarContentFrames.get(windowType)
+ : null;
+ }
+
InsetsState getFixedRotationTransformInsetsState() {
return isFixedRotationTransforming() ? mFixedRotationTransformState.mInsetsState : null;
}
@@ -526,12 +533,12 @@ class WindowToken extends WindowContainer<WindowState> {
if (mFixedRotationTransformState != null) {
return;
}
- final InsetsState insetsState = new InsetsState();
- mDisplayContent.getDisplayPolicy().simulateLayoutDisplay(displayFrames, insetsState,
- mDisplayContent.getConfiguration().uiMode);
mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames,
- insetsState, new Configuration(config), mDisplayContent.getRotation());
+ new Configuration(config), mDisplayContent.getRotation());
mFixedRotationTransformState.mAssociatedTokens.add(this);
+ mDisplayContent.getDisplayPolicy().simulateLayoutDisplay(displayFrames,
+ mFixedRotationTransformState.mInsetsState,
+ mFixedRotationTransformState.mBarContentFrames);
onConfigurationChanged(getParent().getConfiguration());
notifyFixedRotationTransform(true /* enabled */);
}
@@ -554,6 +561,25 @@ class WindowToken extends WindowContainer<WindowState> {
notifyFixedRotationTransform(true /* enabled */);
}
+ /**
+ * Return {@code true} if one of the associated activity is still animating. Otherwise,
+ * return {@code false}.
+ */
+ boolean hasAnimatingFixedRotationTransition() {
+ if (mFixedRotationTransformState == null) {
+ return false;
+ }
+
+ for (int i = mFixedRotationTransformState.mAssociatedTokens.size() - 1; i >= 0; i--) {
+ final ActivityRecord r =
+ mFixedRotationTransformState.mAssociatedTokens.get(i).asActivityRecord();
+ if (r != null && r.isAnimating(TRANSITION | PARENTS)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void finishFixedRotationTransform() {
finishFixedRotationTransform(null /* applyDisplayRotation */);
}
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index e790a196ad64..7132706c4ef1 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -165,6 +165,11 @@ binder::Status BinderIncrementalService::deleteStorage(int32_t storageId) {
return ok();
}
+binder::Status BinderIncrementalService::disableReadLogs(int32_t storageId) {
+ mImpl.disableReadLogs(storageId);
+ return ok();
+}
+
binder::Status BinderIncrementalService::makeDirectory(int32_t storageId, const std::string& path,
int32_t* _aidl_return) {
*_aidl_return = mImpl.makeDir(storageId, path);
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 68549f5a8ff8..10154946d3ee 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -74,7 +74,7 @@ public:
std::vector<uint8_t>* _aidl_return) final;
binder::Status startLoading(int32_t storageId, bool* _aidl_return) final;
binder::Status deleteStorage(int32_t storageId) final;
-
+ binder::Status disableReadLogs(int32_t storageId) final;
binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath,
const std::string& libDirRelativePath,
const std::string& abi, bool extractNativeLibs,
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 885f4d2d34d7..3450c3ae9fb3 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -60,6 +60,7 @@ struct Constants {
static constexpr auto storagePrefix = "st"sv;
static constexpr auto mountpointMdPrefix = ".mountpoint."sv;
static constexpr auto infoMdName = ".info"sv;
+ static constexpr auto readLogsDisabledMarkerName = ".readlogs_disabled"sv;
static constexpr auto libDir = "lib"sv;
static constexpr auto libSuffix = ".so"sv;
static constexpr auto blockSize = 4096;
@@ -172,6 +173,13 @@ std::string makeBindMdName() {
return name;
}
+
+static bool checkReadLogsDisabledMarker(std::string_view root) {
+ const auto markerPath = path::c_str(path::join(root, constants().readLogsDisabledMarkerName));
+ struct stat st;
+ return (::stat(markerPath, &st) == 0);
+}
+
} // namespace
IncrementalService::IncFsMount::~IncFsMount() {
@@ -618,6 +626,32 @@ StorageId IncrementalService::findStorageId(std::string_view path) const {
return it->second->second.storage;
}
+void IncrementalService::disableReadLogs(StorageId storageId) {
+ std::unique_lock l(mLock);
+ const auto ifs = getIfsLocked(storageId);
+ if (!ifs) {
+ LOG(ERROR) << "disableReadLogs failed, invalid storageId: " << storageId;
+ return;
+ }
+ if (!ifs->readLogsEnabled()) {
+ return;
+ }
+ ifs->disableReadLogs();
+ l.unlock();
+
+ const auto metadata = constants().readLogsDisabledMarkerName;
+ if (auto err = mIncFs->makeFile(ifs->control,
+ path::join(ifs->root, constants().mount,
+ constants().readLogsDisabledMarkerName),
+ 0777, idFromMetadata(metadata), {})) {
+ //{.metadata = {metadata.data(), (IncFsSize)metadata.size()}})) {
+ LOG(ERROR) << "Failed to make marker file for storageId: " << storageId;
+ return;
+ }
+
+ setStorageParams(storageId, /*enableReadLogs=*/false);
+}
+
int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLogs) {
const auto ifs = getIfs(storageId);
if (!ifs) {
@@ -627,6 +661,11 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog
const auto& params = ifs->dataLoaderStub->params();
if (enableReadLogs) {
+ if (!ifs->readLogsEnabled()) {
+ LOG(ERROR) << "setStorageParams failed, readlogs disabled for storageId: " << storageId;
+ return -EPERM;
+ }
+
if (auto status = mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage,
params.packageName.c_str());
!status.isOk()) {
@@ -1072,6 +1111,11 @@ std::unordered_set<std::string_view> IncrementalService::adoptMountedInstances()
std::move(control), *this);
cleanupFiles.release(); // ifs will take care of that now
+ // Check if marker file present.
+ if (checkReadLogsDisabledMarker(root)) {
+ ifs->disableReadLogs();
+ }
+
std::vector<std::pair<std::string, metadata::BindPoint>> permanentBindPoints;
auto d = openDir(root);
while (auto e = ::readdir(d.get())) {
@@ -1243,6 +1287,11 @@ bool IncrementalService::mountExistingImage(std::string_view root) {
ifs->mountId = mount.storage().id();
mNextId = std::max(mNextId, ifs->mountId + 1);
+ // Check if marker file present.
+ if (checkReadLogsDisabledMarker(mountTarget)) {
+ ifs->disableReadLogs();
+ }
+
// DataLoader params
DataLoaderParamsParcel dataLoaderParams;
{
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 918531b7921c..a6cc94639c8a 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -94,6 +94,10 @@ public:
Permanent = 1,
};
+ enum StorageFlags {
+ ReadLogsEnabled = 1,
+ };
+
static FileId idFromMetadata(std::span<const uint8_t> metadata);
static inline FileId idFromMetadata(std::span<const char> metadata) {
return idFromMetadata({(const uint8_t*)metadata.data(), metadata.size()});
@@ -116,6 +120,7 @@ public:
int unbind(StorageId storage, std::string_view target);
void deleteStorage(StorageId storage);
+ void disableReadLogs(StorageId storage);
int setStorageParams(StorageId storage, bool enableReadLogs);
int makeFile(StorageId storage, std::string_view path, int mode, FileId id,
@@ -264,6 +269,7 @@ private:
const std::string root;
Control control;
/*const*/ MountId mountId;
+ int32_t flags = StorageFlags::ReadLogsEnabled;
StorageMap storages;
BindMap bindPoints;
DataLoaderStubPtr dataLoaderStub;
@@ -282,6 +288,9 @@ private:
StorageMap::iterator makeStorage(StorageId id);
+ void disableReadLogs() { flags &= ~StorageFlags::ReadLogsEnabled; }
+ int32_t readLogsEnabled() const { return (flags & StorageFlags::ReadLogsEnabled); }
+
static void cleanupFilesystem(std::string_view root);
};
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 26b5094a795a..1ae9e256c9f4 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -929,6 +929,34 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
ASSERT_GE(mDataLoader->setStorageParams(true), 0);
}
+TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndDisabled) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mVold->setIncFsMountOptionsSuccess();
+ mDataLoaderManager->bindToDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ mAppOpsManager->checkPermissionSuccess();
+ EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ // Enabling and then disabling readlogs.
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+ // After setIncFsMountOptions succeeded expecting to start watching.
+ EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
+ // Not expecting callback removal.
+ EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ ASSERT_GE(storageId, 0);
+ ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+ // Now disable.
+ mIncrementalService->disableReadLogs(storageId);
+ ASSERT_EQ(mDataLoader->setStorageParams(true), -EPERM);
+}
+
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 3b38d948b121..6db3233b0266 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -80,6 +80,7 @@
<uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
+ <uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID"/>
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 3062584aee20..b100c8482bf8 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -31,9 +31,10 @@ import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.RemoteException;
-import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+
+import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
import com.android.server.wm.WindowManagerInternal;
@@ -55,7 +56,6 @@ import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -65,6 +65,7 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -100,6 +101,7 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
private BroadcastReceiver mTimeChangedCallback;
private AlarmManager.OnAlarmListener mCustomListener;
private Consumer<PowerSaveState> mPowerSaveConsumer;
+ private TwilightListener mTwilightListener;
@Before
public void setUp() {
@@ -107,6 +109,10 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
when(mContext.checkCallingOrSelfPermission(anyString()))
.thenReturn(PackageManager.PERMISSION_GRANTED);
doAnswer(inv -> {
+ mTwilightListener = (TwilightListener) inv.getArgument(0);
+ return null;
+ }).when(mTwilightManager).registerListener(any(), any());
+ doAnswer(inv -> {
mPowerSaveConsumer = (Consumer<PowerSaveState>) inv.getArgument(1);
return null;
}).when(mLocalPowerManager).registerLowPowerModeObserver(anyInt(), any());
@@ -160,6 +166,37 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void setNightMoveActivated_overridesFunctionCorrectly() throws RemoteException {
+ // set up
+ when(mPowerManager.isInteractive()).thenReturn(false);
+ mService.setNightMode(MODE_NIGHT_NO);
+ assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
+
+ // assume it is day time
+ doReturn(false).when(mTwilightState).isNight();
+
+ // set mode to auto
+ mService.setNightMode(MODE_NIGHT_AUTO);
+
+ // set night mode on overriding current config
+ mService.setNightModeActivated(true);
+
+ assertTrue(mUiManagerService.getConfiguration().isNightModeActive());
+
+ // now it is night time
+ doReturn(true).when(mTwilightState).isNight();
+ mTwilightListener.onTwilightStateChanged(mTwilightState);
+
+ assertTrue(mUiManagerService.getConfiguration().isNightModeActive());
+
+ // now it is next day mid day
+ doReturn(false).when(mTwilightState).isNight();
+ mTwilightListener.onTwilightStateChanged(mTwilightState);
+
+ assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
+ }
+
+ @Test
public void setAutoMode_screenOffRegistered() throws RemoteException {
try {
mService.setNightMode(MODE_NIGHT_NO);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 4ee933a0a5a5..29b96ebdc090 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -794,6 +794,39 @@ public class ActivityRecordTests extends ActivityTestsBase {
}
/**
+ * Verify that when top focused activity is on secondary display, when finishing the top focused
+ * activity on default display, the preferred top stack on default display should be changed by
+ * adjusting focus.
+ */
+ @Test
+ public void testFinishActivityIfPossible_PreferredTopStackChanged() {
+ final ActivityRecord topActivityOnNonTopDisplay =
+ createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
+ ActivityStack topRootableTask = topActivityOnNonTopDisplay.getRootTask();
+ topRootableTask.moveToFront("test");
+ assertTrue(topRootableTask.isTopStackInDisplayArea());
+ assertEquals(topRootableTask, topActivityOnNonTopDisplay.getDisplayArea()
+ .mPreferredTopFocusableStack);
+
+ final ActivityRecord secondaryDisplayActivity =
+ createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
+ topRootableTask = secondaryDisplayActivity.getRootTask();
+ topRootableTask.moveToFront("test");
+ assertTrue(topRootableTask.isTopStackInDisplayArea());
+ assertEquals(topRootableTask,
+ secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableStack);
+
+ // The global top focus activity is on secondary display now.
+ // Finish top activity on default display and verify the next preferred top focusable stack
+ // on default display has changed.
+ topActivityOnNonTopDisplay.setState(RESUMED, "test");
+ topActivityOnNonTopDisplay.finishIfPossible(0 /* resultCode */, null /* resultData */,
+ null /* resultGrants */, "test", false /* oomAdj */);
+ assertEquals(mTask, mStack.getTopMostTask());
+ assertEquals(mStack, mActivity.getDisplayArea().mPreferredTopFocusableStack);
+ }
+
+ /**
* Verify that resumed activity is paused due to finish request.
*/
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index ef28a450695b..a16bd2a72a83 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -38,6 +38,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
@@ -452,6 +453,32 @@ public class AppWindowTokenTests extends WindowTestsBase {
assertFalse(middle.isVisible());
}
+ @Test
+ public void testTransferStartingWindowSetFixedRotation() {
+ mWm.mIsFixedRotationTransformEnabled = true;
+ final ActivityRecord topActivity = createTestActivityRecordForGivenTask(mTask);
+ mTask.positionChildAt(topActivity, POSITION_TOP);
+ mActivity.addStartingWindow(mPackageName,
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+ false);
+ waitUntilHandlersIdle();
+
+ // Make activities to have different rotation from it display and set fixed rotation
+ // transform to activity1.
+ int rotation = (mDisplayContent.getRotation() + 1) % 4;
+ mDisplayContent.setFixedRotationLaunchingApp(mActivity, rotation);
+ doReturn(rotation).when(mDisplayContent)
+ .rotationForActivityInDifferentOrientation(topActivity);
+
+ // Make sure the fixed rotation transform linked to activity2 when adding starting window
+ // on activity2.
+ topActivity.addStartingWindow(mPackageName,
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, mActivity.appToken.asBinder(),
+ false, false, false, true, false);
+ waitUntilHandlersIdle();
+ assertTrue(topActivity.hasFixedRotationTransform());
+ }
+
private ActivityRecord createIsolatedTestActivityRecord() {
final ActivityStack taskStack = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(taskStack, 0 /* userId */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 4ad7dff87072..d3f677ced329 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1144,7 +1144,14 @@ public class DisplayContentTests extends WindowTestsBase {
assertTrue(app.hasFixedRotationTransform(app2));
assertTrue(mDisplayContent.isFixedRotationLaunchingApp(app2));
+ // The fixed rotation transform can only be finished when all animation finished.
+ doReturn(false).when(app2).isAnimating(anyInt(), anyInt());
+ mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app2.token);
+ assertTrue(app.hasFixedRotationTransform());
+ assertTrue(app2.hasFixedRotationTransform());
+
// The display should be rotated after the launch is finished.
+ doReturn(false).when(app).isAnimating(anyInt(), anyInt());
mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app.token);
// The fixed rotation should be cleared and the new rotation is applied to display.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 27c4e9ba8641..1922351ac1eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -57,6 +57,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
+import android.util.SparseArray;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.InsetsState;
@@ -776,15 +777,15 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
}
private void assertSimulateLayoutSameDisplayFrames() {
- final int uiMode = 0;
final String prefix = "";
final InsetsState simulatedInsetsState = new InsetsState();
final DisplayFrames simulatedDisplayFrames = createDisplayFrames();
- mDisplayPolicy.beginLayoutLw(mFrames, uiMode);
+ mDisplayPolicy.beginLayoutLw(mFrames, mDisplayContent.getConfiguration().uiMode);
// Force the display bounds because it is not synced with display frames in policy test.
mDisplayContent.getWindowConfiguration().setBounds(mFrames.mUnrestricted);
mDisplayContent.getInsetsStateController().onPostLayout();
- mDisplayPolicy.simulateLayoutDisplay(simulatedDisplayFrames, simulatedInsetsState, uiMode);
+ mDisplayPolicy.simulateLayoutDisplay(simulatedDisplayFrames, simulatedInsetsState,
+ new SparseArray<>() /* barContentFrames */);
final StringWriter realFramesDump = new StringWriter();
mFrames.dump(prefix, new PrintWriter(realFramesDump));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index ca6679d1eece..243468aba8e8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -349,11 +349,19 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
assertEquals(Configuration.ORIENTATION_PORTRAIT,
homeActivity.getConfiguration().orientation);
- // Home activity won't become top (return to landActivity), so its fixed rotation and the
- // top rotated record should be cleared.
+ // Home activity won't become top (return to landActivity), so the top rotated record should
+ // be cleared.
mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
- assertFalse(homeActivity.hasFixedRotationTransform());
+ assertFalse(mDefaultDisplay.isFixedRotationLaunchingApp(homeActivity));
assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp());
+ // The transform should keep until the transition is done, so the restored configuration
+ // won't be sent to activity and cause unnecessary configuration change.
+ assertTrue(homeActivity.hasFixedRotationTransform());
+
+ // In real case the transition will be executed from RecentsAnimation#finishAnimation.
+ mDefaultDisplay.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(
+ homeActivity.token);
+ assertFalse(homeActivity.hasFixedRotationTransform());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 665cf83cd33c..15b395c8814e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -24,6 +24,7 @@ import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -288,14 +289,29 @@ public class SizeCompatTests extends ActivityTestsBase {
// Move the non-resizable activity to the new display.
mStack.reparent(newDisplay.getDefaultTaskDisplayArea(), true /* onTop */);
- // The configuration bounds should keep the same.
+ // The configuration bounds [820, 0 - 1820, 2500] should keep the same.
assertEquals(origWidth, configBounds.width());
assertEquals(origHeight, configBounds.height());
assertScaled();
+ final Rect newDisplayBounds = newDisplay.getWindowConfiguration().getBounds();
// The scaled bounds should exclude notch area (1000 - 100 == 360 * 2500 / 1000 = 900).
- assertEquals(newDisplay.getBounds().height() - notchHeight,
+ assertEquals(newDisplayBounds.height() - notchHeight,
(int) ((float) mActivity.getBounds().width() * origHeight / origWidth));
+
+ // Recompute the natural configuration in the new display.
+ mActivity.clearSizeCompatMode();
+ mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+ // Because the display cannot rotate, the portrait activity will fit the short side of
+ // display with keeping portrait bounds [200, 0 - 700, 1000] in center.
+ assertEquals(newDisplayBounds.height(), configBounds.height());
+ assertEquals(configBounds.height() * newDisplayBounds.height() / newDisplayBounds.width(),
+ configBounds.width());
+ assertFitted();
+ // The appBounds should be [200, 100 - 700, 1000].
+ final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
+ assertEquals(configBounds.width(), appBounds.width());
+ assertEquals(configBounds.height() - notchHeight, appBounds.height());
}
@Test
@@ -491,7 +507,10 @@ public class SizeCompatTests extends ActivityTestsBase {
mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
final int dw = 1000;
final int dh = 2500;
- setUpDisplaySizeWithApp(dw, dh);
+ final int notchHeight = 200;
+ setUpApp(new TestDisplayContent.Builder(mService, dw, dh).setNotch(notchHeight).build());
+ addStatusBar(mActivity.mDisplayContent);
+
mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_OPEN,
false /* alwaysKeepCurrent */);
mActivity.mDisplayContent.mOpeningApps.add(mActivity);
@@ -503,31 +522,76 @@ public class SizeCompatTests extends ActivityTestsBase {
// Display keeps in original orientation.
assertEquals(Configuration.ORIENTATION_PORTRAIT,
mActivity.mDisplayContent.getConfiguration().orientation);
- // Activity bounds should be [350, 0 - 2150, 1000] in landscape. Its width=1000*1.8=1800.
+ // The width should be restricted by the max aspect ratio = 1000 * 1.8 = 1800.
assertEquals((int) (dw * maxAspect), mActivity.getBounds().width());
- // The bounds should be horizontal centered: (2500-1900)/2=350.
- assertEquals((dh - mActivity.getBounds().width()) / 2, mActivity.getBounds().left);
+ // The notch is at the left side of the landscape activity. The bounds should be horizontal
+ // centered in the remaining area [200, 0 - 2500, 1000], so its left should be
+ // 200 + (2300 - 1800) / 2 = 450. The bounds should be [450, 0 - 2250, 1000].
+ assertEquals(notchHeight + (dh - notchHeight - mActivity.getBounds().width()) / 2,
+ mActivity.getBounds().left);
// The letterbox needs a main window to layout.
- addWindowToActivity(mActivity);
+ final WindowState w = addWindowToActivity(mActivity);
// Compute the frames of the window and invoke {@link ActivityRecord#layoutLetterbox}.
mActivity.mRootWindowContainer.performSurfacePlacement();
- // The letterbox insets should be [350, 0 - 350, 0].
+ // The letterbox insets should be [450, 0 - 250, 0].
assertEquals(new Rect(mActivity.getBounds().left, 0, dh - mActivity.getBounds().right, 0),
mActivity.getLetterboxInsets());
+
+ final StatusBarController statusBarController =
+ mActivity.mDisplayContent.getDisplayPolicy().getStatusBarController();
+ // The activity doesn't fill the display, so the letterbox of the rotated activity is
+ // overlapped with the rotated content frame of status bar. Hence the status bar shouldn't
+ // be transparent.
+ assertFalse(statusBarController.isTransparentAllowed(w));
+
+ // Make the activity fill the display.
+ prepareUnresizable(10 /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
+ w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+ // Refresh the letterbox.
+ mActivity.mRootWindowContainer.performSurfacePlacement();
+
+ // The letterbox should only cover the notch area, so status bar can be transparent.
+ assertEquals(new Rect(notchHeight, 0, 0, 0), mActivity.getLetterboxInsets());
+ assertTrue(statusBarController.isTransparentAllowed(w));
}
- private WindowState addWindowToActivity(ActivityRecord activity) {
+ private static WindowState addWindowToActivity(ActivityRecord activity) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
- mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
+ activity.mWmService, mock(Session.class), new TestIWindow(), params, activity);
WindowTestsBase.makeWindowVisible(w);
w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
- mActivity.addWindow(w);
+ activity.addWindow(w);
return w;
}
+ private static void addStatusBar(DisplayContent displayContent) {
+ final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
+ doReturn(true).when(displayPolicy).hasStatusBar();
+ displayPolicy.onConfigurationChanged();
+
+ final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(
+ WindowManager.LayoutParams.TYPE_STATUS_BAR, displayContent);
+ final WindowManager.LayoutParams attrs =
+ new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_STATUS_BAR);
+ attrs.gravity = android.view.Gravity.TOP;
+ attrs.layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ attrs.setFitInsetsTypes(0 /* types */);
+ final WindowTestUtils.TestWindowState statusBar = new WindowTestUtils.TestWindowState(
+ displayContent.mWmService, mock(Session.class), new TestIWindow(), attrs, token);
+ token.addWindow(statusBar);
+ statusBar.setRequestedSize(displayContent.mBaseDisplayWidth,
+ displayContent.getDisplayUiContext().getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height));
+
+ displayPolicy.addWindowLw(statusBar, attrs);
+ displayPolicy.beginLayoutLw(displayContent.mDisplayFrames,
+ displayContent.getConfiguration().uiMode);
+ }
+
/**
* Setup {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or
* orientation.
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index 4273f5a4a16e..af62ba4b93a1 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -19,8 +19,8 @@ package android.telephony;
import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
-
import android.telephony.Annotation.NetworkType;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
@@ -241,13 +241,13 @@ public final class PhysicalChannelConfig implements Parcelable {
.append(",mCellBandwidthDownlinkKhz=")
.append(mCellBandwidthDownlinkKhz)
.append(",mRat=")
- .append(mRat)
+ .append(TelephonyManager.getNetworkTypeName(mRat))
.append(",mFrequencyRange=")
- .append(mFrequencyRange)
+ .append(ServiceState.frequencyRangeToString(mFrequencyRange))
.append(",mChannelNumber=")
.append(mChannelNumber)
.append(",mContextIds=")
- .append(mContextIds.toString())
+ .append(Arrays.toString(mContextIds))
.append(",mPhysicalCellId=")
.append(mPhysicalCellId)
.append("}")
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index c6b06b467782..9e2ba6875577 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1033,6 +1033,26 @@ public class ServiceState implements Parcelable {
}
/**
+ * Convert frequency range into string
+ *
+ * @param range The cellular frequency range
+ * @return Frequency range in string format
+ *
+ * @hide
+ */
+ public static @NonNull String frequencyRangeToString(@FrequencyRange int range) {
+ switch (range) {
+ case FREQUENCY_RANGE_UNKNOWN: return "UNKNOWN";
+ case FREQUENCY_RANGE_LOW: return "LOW";
+ case FREQUENCY_RANGE_MID: return "MID";
+ case FREQUENCY_RANGE_HIGH: return "HIGH";
+ case FREQUENCY_RANGE_MMWAVE: return "MMWAVE";
+ default:
+ return Integer.toString(range);
+ }
+ }
+
+ /**
* Convert RIL Service State to String
*
* @param serviceState
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fadebaa7bb8a..ee146089b852 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8197,6 +8197,140 @@ public class TelephonyManager {
return false;
}
+ /** @hide */
+ @IntDef({
+ ALLOWED_NETWORK_TYPES_REASON_POWER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AllowedNetworkTypesReason{}
+
+ /**
+ * To indicate allowed network type change is requested by power manager.
+ * Power Manger configuration won't affect the settings configured through
+ * {@link setAllowedNetworkTypes} and will result in allowing network types that are in both
+ * configurations (i.e intersection of both sets).
+ * @hide
+ */
+ public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 0;
+
+ /**
+ * Set the allowed network types of the device and
+ * provide the reason triggering the allowed network change.
+ * This can be called for following reasons
+ * <ol>
+ * <li>Allowed network types control by power manager
+ * {@link #ALLOWED_NETWORK_TYPES_REASON_POWER}
+ * </ol>
+ * This API will result in allowing an intersection of allowed network types for all reasons,
+ * including the configuration done through {@link setAllowedNetworkTypes}.
+ * While this API and {@link setAllowedNetworkTypes} is controlling allowed network types
+ * on device, user preference will still be set through {@link #setPreferredNetworkTypeBitmask}.
+ * Thus resultant network type configured on modem will be an intersection of the network types
+ * from setAllowedNetworkTypesForReason, {@link setAllowedNetworkTypes}
+ * and {@link #setPreferredNetworkTypeBitmask}.
+ *
+ * @param reason the reason the allowed network type change is taking place
+ * @param allowedNetworkTypes The bitmask of allowed network types.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setAllowedNetworkTypesForReason(@AllowedNetworkTypesReason int reason,
+ @NetworkTypeBitMask long allowedNetworkTypes) {
+ if (reason != ALLOWED_NETWORK_TYPES_REASON_POWER) {
+ throw new IllegalArgumentException("invalid AllowedNetworkTypesReason.");
+ }
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setAllowedNetworkTypesForReason(getSubId(), reason,
+ allowedNetworkTypes);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setAllowedNetworkTypesForReason RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the allowed network types for certain reason.
+ *
+ * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a
+ * specific reason. For effective allowed network types configured on device,
+ * query {@link getEffectiveAllowedNetworkTypes}
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *s
+ * @param reason the reason the allowed network type change is taking place
+ * @return the allowed network type bitmask
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public @NetworkTypeBitMask long getAllowedNetworkTypesForReason(
+ @AllowedNetworkTypesReason int reason) {
+ if (reason != ALLOWED_NETWORK_TYPES_REASON_POWER) {
+ throw new IllegalArgumentException("invalid AllowedNetworkTypesReason.");
+ }
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getAllowedNetworkTypesForReason(getSubId(), reason);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getAllowedNetworkTypesForReason RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ return -1;
+ }
+
+ /**
+ * Get bit mask of all network types.
+ *
+ * @return bit mask of all network types
+ * @hide
+ */
+ public static @NetworkTypeBitMask long getAllNetworkTypesBitmask() {
+ return NETWORK_STANDARDS_FAMILY_BITMASK_3GPP | NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2;
+ }
+
+ /**
+ * Get the allowed network types configured on the device.
+ * This API will return an intersection of allowed network types for all reasons,
+ * including the configuration done through setAllowedNetworkTypes
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @return the allowed network type bitmask
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public @NetworkTypeBitMask long getEffectiveAllowedNetworkTypes() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getEffectiveAllowedNetworkTypes(getSubId());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getEffectiveAllowedNetworkTypes RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ return -1;
+ }
+
/**
* Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
*
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 369020033a59..b70937cee8a1 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -956,6 +956,35 @@ interface ITelephony {
boolean setAllowedNetworkTypes(int subId, long allowedNetworkTypes);
/**
+ * Get the allowed network types for certain reason.
+ *
+ * @param subId the id of the subscription.
+ * @param reason the reason the allowed network type change is taking place
+ * @return allowedNetworkTypes the allowed network types.
+ */
+ long getAllowedNetworkTypesForReason(int subId, int reason);
+
+ /**
+ * Get the effective allowed network types on the device. This API will
+ * return an intersection of allowed network types for all reasons,
+ * including the configuration done through setAllowedNetworkTypes
+ *
+ * @param subId the id of the subscription.
+ * @return allowedNetworkTypes the allowed network types.
+ */
+ long getEffectiveAllowedNetworkTypes(int subId);
+
+ /**
+ * Set the allowed network types and provide the reason triggering the allowed network change.
+ *
+ * @param subId the id of the subscription.
+ * @param reason the reason the allowed network type change is taking place
+ * @param allowedNetworkTypes the allowed network types.
+ * @return true on success; false on any failure.
+ */
+ boolean setAllowedNetworkTypesForReason(int subId, int reason, long allowedNetworkTypes);
+
+ /**
* Set the preferred network type.
* Used for device configuration by some CDMA operators.
*