Snap for 6869500 from 8551ec363dcd7c2d7c82c45e89db4922156766ab to rvc-platform-release
Change-Id: I884f9607aea59e8361501bf5d615604a2fb10fe9
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 79d2a81..609083e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -207,7 +207,7 @@
* <p>
* Avoids spamming the system with overly large strings such as full e-mails.
*/
- private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024;
+ private static final int MAX_CHARSEQUENCE_LENGTH = 1024;
/**
* Maximum entries of reply text that are accepted by Builder and friends.
@@ -7830,7 +7830,7 @@
*/
public Message(@NonNull CharSequence text, long timestamp, @Nullable Person sender,
boolean remoteInputHistory) {
- mText = text;
+ mText = safeCharSequence(text);
mTimestamp = timestamp;
mSender = sender;
mRemoteInputHistory = remoteInputHistory;
@@ -7944,7 +7944,7 @@
bundle.putLong(KEY_TIMESTAMP, mTimestamp);
if (mSender != null) {
// Legacy listeners need this
- bundle.putCharSequence(KEY_SENDER, mSender.getName());
+ bundle.putCharSequence(KEY_SENDER, safeCharSequence(mSender.getName()));
bundle.putParcelable(KEY_SENDER_PERSON, mSender);
}
if (mDataMimeType != null) {
diff --git a/core/java/android/os/LocaleList.java b/core/java/android/os/LocaleList.java
index ab4bb0b..9c0bc45 100644
--- a/core/java/android/os/LocaleList.java
+++ b/core/java/android/os/LocaleList.java
@@ -25,6 +25,7 @@
import com.android.internal.annotations.GuardedBy;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
@@ -151,18 +152,18 @@
/**
* Creates a new {@link LocaleList}.
*
+ * If two or more same locales are passed, the repeated locales will be dropped.
* <p>For empty lists of {@link Locale} items it is better to use {@link #getEmptyLocaleList()},
* which returns a pre-constructed empty list.</p>
*
* @throws NullPointerException if any of the input locales is <code>null</code>.
- * @throws IllegalArgumentException if any of the input locales repeat.
*/
public LocaleList(@NonNull Locale... list) {
if (list.length == 0) {
mList = sEmptyList;
mStringRepresentation = "";
} else {
- final Locale[] localeList = new Locale[list.length];
+ final ArrayList<Locale> localeList = new ArrayList<>();
final HashSet<Locale> seenLocales = new HashSet<Locale>();
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.length; i++) {
@@ -170,10 +171,10 @@
if (l == null) {
throw new NullPointerException("list[" + i + "] is null");
} else if (seenLocales.contains(l)) {
- throw new IllegalArgumentException("list[" + i + "] is a repetition");
+ // Dropping duplicated locale entries.
} else {
final Locale localeClone = (Locale) l.clone();
- localeList[i] = localeClone;
+ localeList.add(localeClone);
sb.append(localeClone.toLanguageTag());
if (i < list.length - 1) {
sb.append(',');
@@ -181,7 +182,7 @@
seenLocales.add(localeClone);
}
}
- mList = localeList;
+ mList = localeList.toArray(new Locale[localeList.size()]);
mStringRepresentation = sb.toString();
}
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c383bc7..985829f 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1134,15 +1134,14 @@
if (invokeCallback) {
control.cancel();
}
+ boolean stateChanged = false;
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (runningAnimation.runner == control) {
mRunningAnimations.remove(i);
ArraySet<Integer> types = toInternalType(control.getTypes());
for (int j = types.size() - 1; j >= 0; j--) {
- if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) {
- mHost.notifyInsetsChanged();
- }
+ stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
}
if (invokeCallback && runningAnimation.startDispatched) {
dispatchAnimationEnd(runningAnimation.runner.getAnimation());
@@ -1150,6 +1149,10 @@
break;
}
}
+ if (stateChanged) {
+ mHost.notifyInsetsChanged();
+ updateRequestedState();
+ }
}
private void applyLocalVisibilityOverride() {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 39d20bb..46f2fde 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2774,6 +2774,7 @@
<item>power</item>
<item>restart</item>
<item>logout</item>
+ <item>screenshot</item>
<item>bugreport</item>
</string-array>
@@ -3477,6 +3478,7 @@
mode -->
<string-array translatable="false" name="config_priorityOnlyDndExemptPackages">
<item>com.android.dialer</item>
+ <item>com.android.server.telecom</item>
<item>com.android.systemui</item>
<item>android</item>
</string-array>
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 801cd4d..48695aa 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -27,6 +27,7 @@
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -742,6 +743,20 @@
mController.onControlsChanged(createSingletonControl(ITYPE_IME));
assertEquals(newState.getSource(ITYPE_IME),
mTestHost.getModifiedState().peekSource(ITYPE_IME));
+
+ // The modified frames cannot be updated if there is an animation.
+ mController.onControlsChanged(createSingletonControl(ITYPE_NAVIGATION_BAR));
+ mController.hide(navigationBars());
+ newState = new InsetsState(mController.getState(), true /* copySource */);
+ newState.getSource(ITYPE_NAVIGATION_BAR).getFrame().top--;
+ mController.onStateChanged(newState);
+ assertNotEquals(newState.getSource(ITYPE_NAVIGATION_BAR),
+ mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR));
+
+ // The modified frames can be updated while the animation is done.
+ mController.cancelExistingAnimations();
+ assertEquals(newState.getSource(ITYPE_NAVIGATION_BAR),
+ mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR));
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index b2e9164..016ad45 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -19,6 +19,7 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_GLOBAL_ACTIONS;
import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
@@ -547,7 +548,7 @@
if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
return false;
}
- return true;
+ return action.shouldShow();
}
/**
@@ -962,6 +963,8 @@
@VisibleForTesting
class ScreenshotAction extends SinglePressAction implements LongPressAction {
+ final String KEY_SYSTEM_NAV_2BUTTONS = "system_nav_2buttons";
+
public ScreenshotAction() {
super(R.drawable.ic_screenshot, R.string.global_action_screenshot);
}
@@ -994,6 +997,19 @@
}
@Override
+ public boolean shouldShow() {
+ // Include screenshot in power menu for legacy nav because it is not accessible
+ // through Recents in that mode
+ return is2ButtonNavigationEnabled();
+ }
+
+ boolean is2ButtonNavigationEnabled() {
+ return NAV_BAR_MODE_2BUTTON == mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_navBarInteractionMode);
+ }
+
+
+ @Override
public boolean onLongPress() {
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SCREENRECORD_LONG_PRESS)) {
mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS);
@@ -1616,6 +1632,10 @@
* @return
*/
CharSequence getMessage();
+
+ default boolean shouldShow() {
+ return true;
+ }
}
/**
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 ac8c671..5e2e7c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -49,6 +49,7 @@
import android.util.FeatureFlagUtils;
import android.view.IWindowManager;
import android.view.View;
+import android.view.WindowManagerPolicyConstants;
import android.widget.FrameLayout;
import androidx.test.filters.SmallTest;
@@ -241,6 +242,28 @@
verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS);
}
+ @Test
+ public void testShouldShowScreenshot() {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.integer.config_navBarInteractionMode,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON);
+
+ GlobalActionsDialog.ScreenshotAction screenshotAction =
+ mGlobalActionsDialog.makeScreenshotActionForTesting();
+ assertThat(screenshotAction.shouldShow()).isTrue();
+ }
+
+ @Test
+ public void testShouldNotShowScreenshot() {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.integer.config_navBarInteractionMode,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON);
+
+ GlobalActionsDialog.ScreenshotAction screenshotAction =
+ mGlobalActionsDialog.makeScreenshotActionForTesting();
+ assertThat(screenshotAction.shouldShow()).isFalse();
+ }
+
private void verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent event) {
mTestableLooper.processAllMessages();
verify(mUiEventLogger, times(1))
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 63c721a..c3c655d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4198,13 +4198,9 @@
Iterator<ResolveInfo> iter = matches.iterator();
while (iter.hasNext()) {
final ResolveInfo rInfo = iter.next();
- final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
- if (ps != null) {
- final PermissionsState permissionsState = ps.getPermissionsState();
- if (permissionsState.hasPermission(Manifest.permission.INSTALL_PACKAGES, 0)
- || Build.IS_ENG) {
- continue;
- }
+ if (checkPermission(Manifest.permission.INSTALL_PACKAGES,
+ rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || Build.IS_ENG) {
+ continue;
}
iter.remove();
}
@@ -4380,8 +4376,24 @@
final int[] gids = (flags & PackageManager.GET_GIDS) == 0
? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
// Compute granted permissions only if package has requested permissions
- final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions())
+ Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions())
? Collections.emptySet() : permissionsState.getPermissions(userId);
+ if (state.instantApp) {
+ permissions = new ArraySet<>(permissions);
+ permissions.removeIf(permissionName -> {
+ BasePermission permission = mPermissionManager.getPermissionTEMP(
+ permissionName);
+ if (permission == null) {
+ return true;
+ }
+ if (!permission.isInstant()) {
+ EventLog.writeEvent(0x534e4554, "140256621", UserHandle.getUid(userId,
+ ps.appId), permissionName);
+ return true;
+ }
+ return false;
+ });
+ }
PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId, ps);
@@ -8579,10 +8591,9 @@
private void addPackageHoldingPermissions(ArrayList<PackageInfo> list, PackageSetting ps,
String[] permissions, boolean[] tmp, int flags, int userId) {
int numMatch = 0;
- final PermissionsState permissionsState = ps.getPermissionsState();
for (int i=0; i<permissions.length; i++) {
final String permission = permissions[i];
- if (permissionsState.hasPermission(permission, userId)) {
+ if (checkPermission(permission, ps.name, userId) == PERMISSION_GRANTED) {
tmp[i] = true;
numMatch++;
} else {
@@ -19185,6 +19196,14 @@
final int flags = action.flags;
final boolean systemApp = isSystemApp(ps);
+ // We need to get the permission state before package state is (potentially) destroyed.
+ final SparseBooleanArray hadSuspendAppsPermission = new SparseBooleanArray();
+ // allUserHandles could be null, so call mUserManager.getUserIds() directly which is cached anyway.
+ for (int userId : mUserManager.getUserIds()) {
+ hadSuspendAppsPermission.put(userId, checkPermission(Manifest.permission.SUSPEND_APPS,
+ packageName, userId) == PERMISSION_GRANTED);
+ }
+
final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)
@@ -19251,8 +19270,7 @@
affectedUserIds = resolveUserIds(userId);
}
for (final int affectedUserId : affectedUserIds) {
- if (ps.getPermissionsState().hasPermission(Manifest.permission.SUSPEND_APPS,
- affectedUserId)) {
+ if (hadSuspendAppsPermission.get(affectedUserId)) {
unsuspendForSuspendingPackage(packageName, affectedUserId);
removeAllDistractingPackageRestrictions(affectedUserId);
}
@@ -21017,8 +21035,8 @@
pkgSetting.setEnabled(newState, userId, callingPackage);
if ((newState == COMPONENT_ENABLED_STATE_DISABLED_USER
|| newState == COMPONENT_ENABLED_STATE_DISABLED)
- && pkgSetting.getPermissionsState().hasPermission(
- Manifest.permission.SUSPEND_APPS, userId)) {
+ && checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
+ == PERMISSION_GRANTED) {
// This app should not generally be allowed to get disabled by the UI, but if it
// ever does, we don't want to end up with some of the user's apps permanently
// suspended.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3e9377e..41e48b8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4578,15 +4578,6 @@
return false;
}
- // Check if the activity is on a sleeping display, and if it can turn it ON.
- if (getDisplay().isSleeping()) {
- final boolean canTurnScreenOn = !mSetToSleep || canTurnScreenOn()
- || canShowWhenLocked() || containsDismissKeyguardWindow();
- if (!canTurnScreenOn) {
- return false;
- }
- }
-
// Now check whether it's really visible depending on Keyguard state, and update
// {@link ActivityStack} internal states.
// Inform the method if this activity is the top activity of this stack, but exclude the
@@ -4597,6 +4588,12 @@
final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this,
visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
+ // Check if the activity is on a sleeping display, and if it can turn it ON.
+ // TODO(b/163993448): Do not make activity visible before display awake.
+ if (visibleIgnoringDisplayStatus && getDisplay().isSleeping()) {
+ return !mSetToSleep || canTurnScreenOn();
+ }
+
return visibleIgnoringDisplayStatus;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index e9768a2..2b785c5 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1704,8 +1704,9 @@
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
- if (shouldSleepActivities() && mLastNoHistoryActivity != null &&
- !mLastNoHistoryActivity.finishing) {
+ if (shouldSleepActivities() && mLastNoHistoryActivity != null
+ && !mLastNoHistoryActivity.finishing
+ && mLastNoHistoryActivity != next) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"no-history finish of " + mLastNoHistoryActivity + " on new resume");
mLastNoHistoryActivity.finishIfPossible("resume-no-history", false /* oomAdj */);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index b378621..35ccc43 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1481,9 +1481,10 @@
// anyone interested in this piece of information.
final ActivityStack homeStack = targetTask.getDisplayArea().getRootHomeTask();
final boolean homeTaskVisible = homeStack != null && homeStack.shouldBeVisible(null);
+ final ActivityRecord top = targetTask.getTopNonFinishingActivity();
+ final boolean visible = top != null && top.isVisible();
mService.getTaskChangeNotificationController().notifyActivityRestartAttempt(
- targetTask.getTaskInfo(), homeTaskVisible, clearedTask,
- targetTask.getTopNonFinishingActivity().isVisible());
+ targetTask.getTaskInfo(), homeTaskVisible, clearedTask, visible);
}
}
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 c7b45ef..6ab0697 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1100,6 +1100,34 @@
}
/**
+ * Verify the visibility of a show-when-locked and dismiss keyguard activity on sleeping
+ * display.
+ */
+ @Test
+ public void testDisplaySleeping_activityInvisible() {
+ final KeyguardController keyguardController =
+ mActivity.mStackSupervisor.getKeyguardController();
+ doReturn(true).when(keyguardController).isKeyguardLocked();
+ final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ topActivity.mVisibleRequested = true;
+ topActivity.nowVisible = true;
+ topActivity.setState(RESUMED, "test" /*reason*/);
+ doReturn(true).when(topActivity).containsDismissKeyguardWindow();
+ doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
+ any() /* starting */, anyInt() /* configChanges */,
+ anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
+ topActivity.setShowWhenLocked(true);
+
+ // Verify the top activity is occluded keyguard.
+ assertEquals(topActivity, mStack.topRunningActivity());
+ assertTrue(mStack.topActivityOccludesKeyguard());
+
+ final DisplayContent display = mActivity.mDisplayContent;
+ doReturn(true).when(display).isSleeping();
+ assertFalse(topActivity.shouldBeVisible());
+ }
+
+ /**
* Verify that complete finish request for a show-when-locked activity must ensure the
* keyguard occluded state being updated.
*/