summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-09-15 00:11:40 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-09-15 00:11:40 +0000
commitc53e71dc397de7486c9a8899f71598c3c3a18d44 (patch)
tree56b7a129a0b006b5ee7ab88c866d8a9293d278ee
parentcebf5c06997b64f4e47a1611edb5f97044509d76 (diff)
parent39627225836a334d785e2176ca517effe806ec3a (diff)
downloadbase-android12-s2-release.tar.gz
Merge cherrypicks of [15831545, 15831526, 15831634, 15831684, 15831293, 15831546, 15831847, 15831808, 15831638, 15831639, 15831558, 15831793, 15831794, 15831795, 15831796, 15831797, 15831798, 15831799, 15831800, 15831801, 15831802, 15831803, 15831804, 15831640, 15831849, 15831810, 15831811, 15831850, 15831641, 15831805, 15831812, 15831642, 15831813, 15831851, 15831852, 15831887, 15831888, 15831559, 15831814, 15831815, 15831853, 15831854, 15831855, 15831315] into sc-releaseandroid-platform-12.0.0_r1android-12.0.0_r9android-12.0.0_r8android-12.0.0_r11android-12.0.0_r10android12-s2-releaseandroid12-release
Change-Id: I6b2fbc1d2e4c5f02209d5d3e86b453369df2132f
-rw-r--r--core/java/android/accounts/Account.java7
-rw-r--r--core/java/android/app/ActivityThread.java12
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java5
-rw-r--r--media/java/android/media/PlayerBase.java7
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java6
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java5
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java12
-rw-r--r--services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/Permission.java7
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java25
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java23
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java9
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java41
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java69
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java68
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java34
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java29
32 files changed, 452 insertions, 140 deletions
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 0d6a07938e95..e6cdcc0ee742 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -31,6 +31,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import java.util.Objects;
import java.util.Set;
/**
@@ -86,6 +87,12 @@ public class Account implements Parcelable {
if (TextUtils.isEmpty(type)) {
throw new IllegalArgumentException("the type must not be empty: " + type);
}
+ if (name.length() > 200) {
+ throw new IllegalArgumentException("account name is longer than 200 characters");
+ }
+ if (type.length() > 200) {
+ throw new IllegalArgumentException("account type is longer than 200 characters");
+ }
this.name = name;
this.type = type;
this.accessId = accessId;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0c64c86daf3e..de0fef0e74a2 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -464,11 +464,7 @@ public final class ActivityThread extends ClientTransactionHandler
@Override
public int hashCode() {
- return hashCode(authority, userId);
- }
-
- public static int hashCode(final String auth, final int userIdent) {
- return ((auth != null) ? auth.hashCode() : 0) ^ userIdent;
+ return ((authority != null) ? authority.hashCode() : 0) ^ userId;
}
}
@@ -490,7 +486,7 @@ public final class ActivityThread extends ClientTransactionHandler
// Note we never removes items from this map but that's okay because there are only so many
// users and so many authorities.
@GuardedBy("mGetProviderKeys")
- final SparseArray<ProviderKey> mGetProviderKeys = new SparseArray<>();
+ final ArrayMap<ProviderKey, ProviderKey> mGetProviderKeys = new ArrayMap<>();
final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
= new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
@@ -7015,11 +7011,11 @@ public final class ActivityThread extends ClientTransactionHandler
}
private ProviderKey getGetProviderKey(String auth, int userId) {
- final int key = ProviderKey.hashCode(auth, userId);
+ final ProviderKey key = new ProviderKey(auth, userId);
synchronized (mGetProviderKeys) {
ProviderKey lock = mGetProviderKeys.get(key);
if (lock == null) {
- lock = new ProviderKey(auth, userId);
+ lock = key;
mGetProviderKeys.put(key, lock);
}
return lock;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index bbb550fd6343..5a5fac4a7664 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1329,7 +1329,10 @@ public final class BluetoothDevice implements Parcelable, Attributable {
if (alias == null) {
return getName();
}
- return alias;
+ return alias
+ .replace('\t', ' ')
+ .replace('\n', ' ')
+ .replace('\r', ' ');
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 86ed50bacb63..72ee00f03774 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -102,6 +102,13 @@ public abstract class PlayerBase {
mState = AudioPlaybackConfiguration.PLAYER_STATE_IDLE;
};
+ /** @hide */
+ public int getPlayerIId() {
+ synchronized (mLock) {
+ return mPlayerIId;
+ }
+ }
+
/**
* Call from derived class when instantiation / initialization is successful
*/
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index c1a0a9a92cc2..b4cafd8548f4 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -93,9 +93,9 @@ public class CompanionDeviceActivity extends Activity {
final DeviceFilterPair selectedDevice = getService().mDevicesFound.get(0);
setTitle(Html.fromHtml(getString(
R.string.confirmation_title,
- getCallingAppName(),
- profileName,
- selectedDevice.getDisplayName()), 0));
+ Html.escapeHtml(getCallingAppName()),
+ Html.escapeHtml(selectedDevice.getDisplayName())), 0));
+
mPairButton = findViewById(R.id.button_pair);
mPairButton.setOnClickListener(v -> onDeviceConfirmed(getService().mSelectedDevice));
getService().mSelectedDevice = selectedDevice;
@@ -108,8 +108,8 @@ public class CompanionDeviceActivity extends Activity {
mPairButton = findViewById(R.id.button_pair);
mPairButton.setVisibility(View.GONE);
setTitle(Html.fromHtml(getString(R.string.chooser_title,
- profileName,
- getCallingAppName()), 0));
+ Html.escapeHtml(profileName),
+ Html.escapeHtml(getCallingAppName())), 0));
mDeviceListView = findViewById(R.id.device_list);
mDevicesAdapter = new DevicesAdapter();
mDeviceListView.setAdapter(mDevicesAdapter);
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 89786ee880ad..a617850ef0ae 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -139,7 +139,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
+ " with ducking", e);
}
player.start();
- if (DEBUG) { Log.d(mTag, "player.start"); }
+ if (DEBUG) { Log.d(mTag, "player.start piid:" + player.getPlayerIId()); }
} catch (Exception e) {
if (player != null) {
player.release();
@@ -155,7 +155,13 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
mPlayer = player;
}
if (mp != null) {
- if (DEBUG) { Log.d(mTag, "mPlayer.release"); }
+ if (DEBUG) {
+ Log.d(mTag, "mPlayer.pause+release piid:" + player.getPlayerIId());
+ }
+ mp.pause();
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ie) { }
mp.release();
}
this.notify();
@@ -244,6 +250,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
try {
mp.stop();
} catch (Exception e) { }
+ if (DEBUG) {
+ Log.i(mTag, "About to release MediaPlayer piid:"
+ + mp.getPlayerIId() + " due to notif cancelled");
+ }
mp.release();
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
@@ -284,7 +294,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
public void onCompletion(MediaPlayer mp) {
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
- if (DEBUG) Log.d(mTag, "onCompletion() abandonning AudioFocus");
+ if (DEBUG) Log.d(mTag, "onCompletion() abandoning AudioFocus");
mAudioManagerWithAudioFocus.abandonAudioFocus(null);
mAudioManagerWithAudioFocus = null;
} else {
@@ -310,6 +320,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
}
}
if (mp != null) {
+ if (DEBUG) {
+ Log.i("NotificationPlayer", "About to release MediaPlayer piid:"
+ + mp.getPlayerIId() + " due to onCompletion");
+ }
mp.release();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 541ee2c4fe8f..4a75810f86db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -51,6 +51,7 @@ import com.android.systemui.qs.external.TileServices;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -95,6 +96,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
private final UiEventLogger mUiEventLogger;
private final InstanceIdSequence mInstanceIdSequence;
private final CustomTileStatePersister mCustomTileStatePersister;
+ private final FeatureFlags mFeatureFlags;
private final List<Callback> mCallbacks = new ArrayList<>();
private AutoTileManager mAutoTiles;
@@ -122,7 +124,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
UiEventLogger uiEventLogger,
UserTracker userTracker,
SecureSettings secureSettings,
- CustomTileStatePersister customTileStatePersister
+ CustomTileStatePersister customTileStatePersister,
+ FeatureFlags featureFlags
) {
mIconController = iconController;
mContext = context;
@@ -144,6 +147,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
mUserTracker = userTracker;
mSecureSettings = secureSettings;
mCustomTileStatePersister = customTileStatePersister;
+ mFeatureFlags = featureFlags;
mainHandler.post(() -> {
// This is technically a hack to avoid circular dependency of
@@ -265,7 +269,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) {
newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode);
}
- final List<String> tileSpecs = loadTileSpecs(mContext, newValue);
+ final List<String> tileSpecs = loadTileSpecs(mContext, newValue, mFeatureFlags);
int currentUser = mUserTracker.getUserId();
if (currentUser != mCurrentUser) {
mUserContext = mUserTracker.getUserContext();
@@ -334,7 +338,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
if (newTiles.isEmpty() && !tileSpecs.isEmpty()) {
// If we didn't manage to create any tiles, set it to empty (default)
Log.d(TAG, "No valid tiles on tuning changed. Setting to default.");
- changeTiles(currentSpecs, loadTileSpecs(mContext, ""));
+ changeTiles(currentSpecs, loadTileSpecs(mContext, "", mFeatureFlags));
} else {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onTilesChanged();
@@ -389,7 +393,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
private void changeTileSpecs(Predicate<List<String>> changeFunction) {
final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser);
- final List<String> tileSpecs = loadTileSpecs(mContext, setting);
+ final List<String> tileSpecs = loadTileSpecs(mContext, setting, mFeatureFlags);
if (changeFunction.test(tileSpecs)) {
saveTilesToSettings(tileSpecs);
}
@@ -478,7 +482,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
throw new RuntimeException("Default factory didn't create view for " + tile.getTileSpec());
}
- protected static List<String> loadTileSpecs(Context context, String tileList) {
+ protected static List<String> loadTileSpecs(
+ Context context, String tileList, FeatureFlags featureFlags) {
final Resources res = context.getResources();
if (TextUtils.isEmpty(tileList)) {
@@ -511,6 +516,21 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
}
}
}
+ if (featureFlags.isProviderModelSettingEnabled()) {
+ if (!tiles.contains("internet")) {
+ if (tiles.contains("wifi")) {
+ // Replace the WiFi with Internet, and remove the Cell
+ tiles.set(tiles.indexOf("wifi"), "internet");
+ tiles.remove("cell");
+ } else if (tiles.contains("cell")) {
+ // Replace the Cell with Internet
+ tiles.set(tiles.indexOf("cell"), "internet");
+ }
+ } else {
+ tiles.remove("wifi");
+ tiles.remove("cell");
+ }
+ }
return tiles;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 3c2f35b954ea..f2832b3d45ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -41,6 +41,7 @@ import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.leak.GarbageMonitor;
import java.util.ArrayList;
@@ -62,6 +63,7 @@ public class TileQueryHelper {
private final Executor mBgExecutor;
private final Context mContext;
private final UserTracker mUserTracker;
+ private final FeatureFlags mFeatureFlags;
private TileStateListener mListener;
private boolean mFinished;
@@ -71,12 +73,14 @@ public class TileQueryHelper {
Context context,
UserTracker userTracker,
@Main Executor mainExecutor,
- @Background Executor bgExecutor
+ @Background Executor bgExecutor,
+ FeatureFlags featureFlags
) {
mContext = context;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
mUserTracker = userTracker;
+ mFeatureFlags = featureFlags;
}
public void setListener(TileStateListener listener) {
@@ -117,6 +121,10 @@ public class TileQueryHelper {
}
final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
+ if (mFeatureFlags.isProviderModelSettingEnabled()) {
+ possibleTiles.remove("cell");
+ possibleTiles.remove("wifi");
+ }
for (String spec : possibleTiles) {
// Only add current and stock tiles that can be created from QSFactoryImpl.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 86c90c7bcb2e..9eb95c409009 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.row;
-import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -28,15 +27,12 @@ import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.ViewState;
public class FooterView extends StackScrollerDecorView {
- private final int mClearAllTopPadding;
private FooterViewButton mDismissButton;
private FooterViewButton mManageButton;
private boolean mShowHistory;
public FooterView(Context context, AttributeSet attrs) {
super(context, attrs);
- mClearAllTopPadding = context.getResources().getDimensionPixelSize(
- R.dimen.clear_all_padding_top);
}
@Override
@@ -55,11 +51,6 @@ public class FooterView extends StackScrollerDecorView {
mManageButton = findViewById(R.id.manage_text);
}
- public void setTextColor(@ColorInt int color) {
- mManageButton.setTextColor(color);
- mDismissButton.setTextColor(color);
- }
-
public void setManageButtonClickListener(OnClickListener listener) {
mManageButton.setOnClickListener(listener);
}
@@ -95,21 +86,25 @@ public class FooterView extends StackScrollerDecorView {
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- int textColor = getResources().getColor(R.color.notif_pill_text);
- Resources.Theme theme = getContext().getTheme();
- mDismissButton.setBackground(
- getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
- mDismissButton.setTextColor(textColor);
- mManageButton.setBackground(
- getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
- mManageButton = findViewById(R.id.manage_text);
+ updateColors();
mDismissButton.setText(R.string.clear_all_notifications_text);
- mManageButton.setTextColor(textColor);
mDismissButton.setContentDescription(
mContext.getString(R.string.accessibility_clear_all));
showHistory(mShowHistory);
}
+ /**
+ * Update the text and background colors for the current color palette and night mode setting.
+ */
+ public void updateColors() {
+ Resources.Theme theme = mContext.getTheme();
+ int textColor = getResources().getColor(R.color.notif_pill_text, theme);
+ mDismissButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+ mDismissButton.setTextColor(textColor);
+ mManageButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+ mManageButton.setTextColor(textColor);
+ }
+
@Override
public ExpandableViewState createExpandableViewState() {
return new FooterViewState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 289c32f17b31..0660daab3720 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -4231,7 +4231,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
final @ColorInt int textColor =
Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
mSectionsManager.setHeaderForegroundColor(textColor);
- mFooterView.setTextColor(textColor);
+ mFooterView.updateColors();
mEmptyShadeView.setTextColor(textColor);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 3ee3e55c749a..7f89b2629a6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -139,7 +139,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
() -> mock(AutoTileManager.class), mock(DumpManager.class),
mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
- mock(SecureSettings.class), mock(CustomTileStatePersister.class));
+ mock(SecureSettings.class), mock(CustomTileStatePersister.class), mFeatureFlags);
qs.setHost(host);
qs.setListening(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 9e97f801be3e..4cbad5f15c5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -63,6 +63,7 @@ import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -124,6 +125,8 @@ public class QSTileHostTest extends SysuiTestCase {
private SecureSettings mSecureSettings;
@Mock
private CustomTileStatePersister mCustomTileStatePersister;
+ @Mock
+ private FeatureFlags mFeatureFlags;
private Handler mHandler;
private TestableLooper mLooper;
@@ -137,9 +140,9 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
- mSecureSettings, mCustomTileStatePersister);
+ mSecureSettings, mCustomTileStatePersister, mFeatureFlags);
setUpTileFactory();
-
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false);
when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt()))
.thenReturn("");
}
@@ -169,13 +172,13 @@ public class QSTileHostTest extends SysuiTestCase {
@Test
public void testLoadTileSpecs_emptySetting() {
- List<String> tiles = QSTileHost.loadTileSpecs(mContext, "");
+ List<String> tiles = QSTileHost.loadTileSpecs(mContext, "", mFeatureFlags);
assertFalse(tiles.isEmpty());
}
@Test
public void testLoadTileSpecs_nullSetting() {
- List<String> tiles = QSTileHost.loadTileSpecs(mContext, null);
+ List<String> tiles = QSTileHost.loadTileSpecs(mContext, null, mFeatureFlags);
assertFalse(tiles.isEmpty());
}
@@ -189,6 +192,55 @@ public class QSTileHostTest extends SysuiTestCase {
}
@Test
+ public void testRemoveWifiAndCellularWithoutInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2");
+
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testRemoveWifiAndCellularWithInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2, internet");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testRemoveWifiWithoutInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, wifi, spec2");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testRemoveCellWithInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, spec2, cell, internet");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testNoWifiNoCellularNoInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ }
+
+ @Test
public void testSpecWithInvalidDoesNotUseDefault() {
mContext.getOrCreateTestableResources()
.addOverride(R.string.quick_settings_tiles, "spec1,spec2");
@@ -321,7 +373,7 @@ public class QSTileHostTest extends SysuiTestCase {
@Test
public void testLoadTileSpec_repeated() {
- List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2");
+ List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2", mFeatureFlags);
assertEquals(2, specs.size());
assertEquals("spec1", specs.get(0));
@@ -332,7 +384,7 @@ public class QSTileHostTest extends SysuiTestCase {
public void testLoadTileSpec_repeatedInDefault() {
mContext.getOrCreateTestableResources()
.addOverride(R.string.quick_settings_tiles_default, "spec1,spec1");
- List<String> specs = QSTileHost.loadTileSpecs(mContext, "default");
+ List<String> specs = QSTileHost.loadTileSpecs(mContext, "default", mFeatureFlags);
// Remove spurious tiles, like dbg:mem
specs.removeIf(spec -> !"spec1".equals(spec));
@@ -343,7 +395,7 @@ public class QSTileHostTest extends SysuiTestCase {
public void testLoadTileSpec_repeatedDefaultAndSetting() {
mContext.getOrCreateTestableResources()
.addOverride(R.string.quick_settings_tiles_default, "spec1");
- List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1");
+ List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1", mFeatureFlags);
// Remove spurious tiles, like dbg:mem
specs.removeIf(spec -> !"spec1".equals(spec));
@@ -371,11 +423,12 @@ public class QSTileHostTest extends SysuiTestCase {
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
UiEventLogger uiEventLogger, UserTracker userTracker,
- SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister) {
+ SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister,
+ FeatureFlags featureFlags) {
super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
tunerService, autoTiles, dumpManager, broadcastDispatcher,
Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings,
- customTileStatePersister);
+ customTileStatePersister, featureFlags);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 4efcc5c3fc73..c5b67091d197 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -58,6 +58,7 @@ import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -108,6 +109,8 @@ public class TileQueryHelperTest extends SysuiTestCase {
private PackageManager mPackageManager;
@Mock
private UserTracker mUserTracker;
+ @Mock
+ private FeatureFlags mFeatureFlags;
@Captor
private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
@@ -133,12 +136,12 @@ public class TileQueryHelperTest extends SysuiTestCase {
}
}
).when(mQSTileHost).createTile(anyString());
-
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false);
FakeSystemClock clock = new FakeSystemClock();
mMainExecutor = new FakeExecutor(clock);
mBgExecutor = new FakeExecutor(clock);
mTileQueryHelper = new TileQueryHelper(
- mContext, mUserTracker, mMainExecutor, mBgExecutor);
+ mContext, mUserTracker, mMainExecutor, mBgExecutor, mFeatureFlags);
mTileQueryHelper.setListener(mListener);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 2b1840462291..01fa222896d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -48,6 +48,7 @@ import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -98,6 +99,8 @@ public class TileServicesTest extends SysuiTestCase {
private UserTracker mUserTracker;
@Mock
private SecureSettings mSecureSettings;
+ @Mock
+ private FeatureFlags mFeatureFlags;
@Before
public void setUp() throws Exception {
@@ -119,7 +122,8 @@ public class TileServicesTest extends SysuiTestCase {
mUiEventLogger,
mUserTracker,
mSecureSettings,
- mock(CustomTileStatePersister.class));
+ mock(CustomTileStatePersister.class),
+ mFeatureFlags);
mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
mUserTracker);
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index a6a8cf018eef..400b084ee966 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1833,6 +1833,11 @@ public class AccountManagerService
+ ", skipping since the account already exists");
return false;
}
+ if (accounts.accountsDb.findAllDeAccounts().size() > 100) {
+ Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
+ + ", skipping since more than 50 accounts on device exist");
+ return false;
+ }
long accountId = accounts.accountsDb.insertCeAccount(account, password);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index dc955337fdbc..3e52f5e07e62 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2582,14 +2582,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (mCurToken != null) {
- try {
- if (DEBUG) {
- Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
- + mCurTokenDisplayId);
- }
- mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
- } catch (RemoteException e) {
+ if (DEBUG) {
+ Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
+ + mCurTokenDisplayId);
}
+ mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */,
+ false /* animateExit */, mCurTokenDisplayId);
// Set IME window status as invisible when unbind current method.
mImeWindowVis = 0;
mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index 3019439a430b..5643873bef4d 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -215,7 +215,7 @@ public class DefaultCrossProfileIntentFiltersUtils {
private static final DefaultCrossProfileIntentFilter RECOGNIZE_SPEECH =
new DefaultCrossProfileIntentFilter.Builder(
DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
- /* flags= */0,
+ /* flags= */ ONLY_IF_NO_MATCH_FOUND,
/* letsPersonalDataIntoProfile= */ false)
.addAction(ACTION_RECOGNIZE_SPEECH)
.addCategory(Intent.CATEGORY_DEFAULT)
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index cda48063e914..94e551a11dae 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -480,9 +480,10 @@ public final class Permission {
r.append("DUP:");
r.append(permissionInfo.name);
}
- if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) {
- // If this is a runtime permission and the owner has changed, or this wasn't a runtime
- // permission, then permission state should be cleaned up
+ if ((permission.isInternal() && ownerChanged)
+ || (permission.isRuntime() && (ownerChanged || wasNonRuntime))) {
+ // If this is an internal/runtime permission and the owner has changed, or this wasn't a
+ // runtime permission, then permission state should be cleaned up.
permission.mDefinitionChanged = true;
}
if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 1133faabcf69..7b12709e4efd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1643,7 +1643,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
isRolePermission = permission.isRole();
}
final boolean mayRevokeRolePermission = isRolePermission
- && mayManageRolePermission(callingUid);
+ // Allow ourselves to revoke role permissions due to definition changes.
+ && (callingUid == Process.myUid() || mayManageRolePermission(callingUid));
final boolean isRuntimePermission;
synchronized (mLock) {
@@ -2321,11 +2322,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int permNum = 0; permNum < numPermissions; permNum++) {
final String permName = permissionsToRevoke.get(permNum);
+ final boolean isInternalPermission;
synchronized (mLock) {
final Permission bp = mRegistry.getPermission(permName);
- if (bp == null || !bp.isRuntime()) {
+ if (bp == null || !(bp.isInternal() || bp.isRuntime())) {
continue;
}
+ isInternalPermission = bp.isInternal();
}
mPackageManagerInt.forEachPackage(pkg -> {
final String packageName = pkg.getPackageName();
@@ -2345,12 +2348,18 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (permissionState == PackageManager.PERMISSION_GRANTED
&& (flags & flagMask) == 0) {
final int uid = UserHandle.getUid(userId, appId);
- EventLog.writeEvent(0x534e4554, "154505240", uid,
- "Revoking permission " + permName + " from package "
- + packageName + " due to definition change");
- EventLog.writeEvent(0x534e4554, "168319670", uid,
- "Revoking permission " + permName + " from package "
- + packageName + " due to definition change");
+ if (isInternalPermission) {
+ EventLog.writeEvent(0x534e4554, "195338390", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ } else {
+ EventLog.writeEvent(0x534e4554, "154505240", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ EventLog.writeEvent(0x534e4554, "168319670", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ }
Slog.e(TAG, "Revoking permission " + permName + " from package "
+ packageName + " due to definition change");
try {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 36a854e5374c..28947083854b 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2304,10 +2304,9 @@ public final class TvInputManagerService extends SystemService {
public void requestChannelBrowsable(Uri channelUri, int userId)
throws RemoteException {
final String callingPackageName = getCallingPackageName();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, "requestChannelBrowsable");
final long identity = Binder.clearCallingIdentity();
- final int callingUid = Binder.getCallingUid();
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
- userId, "requestChannelBrowsable");
try {
Intent intent = new Intent(TvContract.ACTION_CHANNEL_BROWSABLE_REQUESTED);
List<ResolveInfo> list = getContext().getPackageManager()
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 308df2f4e9a0..c2cfe0b7bd92 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -656,6 +656,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean mLastImeShown;
/**
+ * When set to true, the IME insets will be frozen until the next app becomes IME input target.
+ * @see InsetsPolicy#adjustVisibilityForIme
+ */
+ boolean mImeInsetsFrozenUntilStartInput;
+
+ /**
* A flag to determine if this AR is in the process of closing or entering PIP. This is needed
* to help AR know that the app is in the process of closing but hasn't yet started closing on
* the WM side.
@@ -1363,6 +1369,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
if (newTask != null && isState(RESUMED)) {
newTask.setResumedActivity(this, "onParentChanged");
+ mImeInsetsFrozenUntilStartInput = false;
}
if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -4759,6 +4766,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
&& imeInputTarget.getWindow().mActivityRecord == this
&& mDisplayContent.mInputMethodWindow != null
&& mDisplayContent.mInputMethodWindow.isVisible();
+ mImeInsetsFrozenUntilStartInput = true;
}
final DisplayContent displayContent = getDisplayContent();
@@ -5877,6 +5885,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// closing activity having to wait until idle timeout to be stopped or destroyed if the
// next activity won't report idle (e.g. repeated view animation).
mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
+
+ // If the activity is visible, but no windows are eligible to start input, unfreeze
+ // to avoid permanently frozen IME insets.
+ if (mImeInsetsFrozenUntilStartInput && getWindow(
+ win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags))
+ == null) {
+ mImeInsetsFrozenUntilStartInput = false;
+ }
}
}
@@ -7792,6 +7808,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ @Override
+ void onResize() {
+ // Reset freezing IME insets flag when the activity resized.
+ mImeInsetsFrozenUntilStartInput = false;
+ super.onResize();
+ }
+
/** Returns true if the configuration is compatible with this activity. */
boolean isConfigurationCompatible(Configuration config) {
final int orientation = getRequestedOrientation();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index dbc1116ad389..9335846e7805 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1165,10 +1165,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- WindowToken removeWindowToken(IBinder binder) {
+ WindowToken removeWindowToken(IBinder binder, boolean animateExit) {
final WindowToken token = mTokenMap.remove(binder);
if (token != null && token.asActivityRecord() == null) {
- token.setExiting();
+ token.setExiting(animateExit);
}
return token;
}
@@ -1252,7 +1252,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
void removeAppToken(IBinder binder) {
- final WindowToken token = removeWindowToken(binder);
+ final WindowToken token = removeWindowToken(binder, true /* animateExit */);
if (token == null) {
Slog.w(TAG_WM, "removeAppToken: Attempted to remove non-existing token: " + binder);
return;
@@ -3971,6 +3971,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void updateImeInputAndControlTarget(WindowState target) {
if (mImeInputTarget != target) {
ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target);
+ if (target != null && target.mActivityRecord != null) {
+ target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
+ }
setImeInputTarget(target);
updateImeControlTarget();
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index f2f192686ad5..a8e1c1cda72b 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -211,7 +211,7 @@ class InsetsPolicy {
InsetsState getInsetsForWindow(WindowState target) {
final InsetsState originalState = mStateController.getInsetsForWindow(target);
final InsetsState state = adjustVisibilityForTransientTypes(originalState);
- return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state;
+ return adjustVisibilityForIme(target, state, state == originalState);
}
/**
@@ -241,16 +241,37 @@ class InsetsPolicy {
return state;
}
- // Navigation bar insets is always visible to IME.
- private static InsetsState adjustVisibilityForIme(InsetsState originalState,
+ private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
boolean copyState) {
- final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
- if (originalNavSource != null && !originalNavSource.isVisible()) {
- final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
- final InsetsSource navSource = new InsetsSource(originalNavSource);
- navSource.setVisible(true);
- state.addSource(navSource);
- return state;
+ if (w.mIsImWindow) {
+ // Navigation bar insets is always visible to IME.
+ final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
+ if (originalNavSource != null && !originalNavSource.isVisible()) {
+ final InsetsState state = copyState ? new InsetsState(originalState)
+ : originalState;
+ final InsetsSource navSource = new InsetsSource(originalNavSource);
+ navSource.setVisible(true);
+ state.addSource(navSource);
+ return state;
+ }
+ } else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
+ // During switching tasks with gestural navigation, if the IME is attached to
+ // one app window on that time, even the next app window is behind the IME window,
+ // conceptually the window should not receive the IME insets if the next window is
+ // not eligible IME requester and ready to show IME on top of it.
+ final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
+ final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
+
+ if (shouldImeAttachedToApp && originalImeSource != null) {
+ final boolean imeVisibility =
+ w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
+ final InsetsState state = copyState ? new InsetsState(originalState)
+ : originalState;
+ final InsetsSource imeSource = new InsetsSource(originalImeSource);
+ imeSource.setVisible(imeVisibility);
+ state.addSource(imeSource);
+ return state;
+ }
}
return originalState;
}
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 194f48f57cc4..b54e8b7a7b4e 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -66,8 +66,8 @@ class WallpaperWindowToken extends WindowToken {
}
@Override
- void setExiting() {
- super.setExiting();
+ void setExiting(boolean animateExit) {
+ super.setExiting(animateExit);
mDisplayContent.mWallpaperController.removeWallpaperToken(this);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 47087cfbd147..4fac05c349c5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -445,8 +445,21 @@ public abstract class WindowManagerInternal {
* @param removeWindows Whether to also remove the windows associated with the token.
* @param displayId The display to remove the token from.
*/
+ public final void removeWindowToken(android.os.IBinder token, boolean removeWindows,
+ int displayId) {
+ removeWindowToken(token, removeWindows, true /* animateExit */, displayId);
+ }
+
+ /**
+ * Removes a window token.
+ *
+ * @param token The toke to remove.
+ * @param removeWindows Whether to also remove the windows associated with the token.
+ * @param animateExit Whether to play the windows exit animation after the token removal.
+ * @param displayId The display to remove the token from.
+ */
public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows,
- int displayId);
+ boolean animateExit, int displayId);
/**
* Registers a listener to be notified about app transition events.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1ec9187d7a76..9caef70f6b51 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2816,6 +2816,31 @@ public class WindowManagerService extends IWindowManager.Stub
}
+ void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
+ int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+
+ if (dc == null) {
+ ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
+ + " for non-exiting displayId=%d", binder, displayId);
+ return;
+ }
+ final WindowToken token = dc.removeWindowToken(binder, animateExit);
+ if (token == null) {
+ ProtoLog.w(WM_ERROR,
+ "removeWindowToken: Attempted to remove non-existing token: %s",
+ binder);
+ return;
+ }
+
+ if (removeWindows) {
+ token.removeAllWindowsIfPossible();
+ }
+ dc.getInputMonitor().updateInputWindowsLw(true /* force */);
+ }
+ }
+
@Override
public void removeWindowToken(IBinder binder, int displayId) {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) {
@@ -2823,23 +2848,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
final long origId = Binder.clearCallingIdentity();
try {
- synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
-
- if (dc == null) {
- ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
- + " for non-exiting displayId=%d", binder, displayId);
- return;
- }
- final WindowToken token = dc.removeWindowToken(binder);
- if (token == null) {
- ProtoLog.w(WM_ERROR,
- "removeWindowToken: Attempted to remove non-existing token: %s",
- binder);
- return;
- }
- dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
- }
+ removeWindowToken(binder, false /* removeWindows */, true /* animateExit */, displayId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -7536,28 +7545,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void removeWindowToken(IBinder binder, boolean removeWindows, int displayId) {
- synchronized (mGlobalLock) {
- if (removeWindows) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc == null) {
- ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
- + " for non-exiting displayId=%d", binder, displayId);
- return;
- }
-
- final WindowToken token = dc.removeWindowToken(binder);
- if (token == null) {
- ProtoLog.w(WM_ERROR,
- "removeWindowToken: Attempted to remove non-existing token: %s",
- binder);
- return;
- }
-
- token.removeAllWindowsIfPossible();
- }
- WindowManagerService.this.removeWindowToken(binder, displayId);
- }
+ public void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
+ int displayId) {
+ WindowManagerService.this.removeWindowToken(binder, removeWindows, animateExit,
+ displayId);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c3fc99554bcc..5e042efa2f11 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2180,11 +2180,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- boolean onSetAppExiting() {
+ boolean onSetAppExiting(boolean animateExit) {
final DisplayContent displayContent = getDisplayContent();
boolean changed = false;
- if (isVisibleNow()) {
+ if (!animateExit) {
+ // Hide the window permanently if no window exist animation is performed, so we can
+ // avoid the window surface becoming visible again unexpectedly during the next
+ // relayout.
+ mPermanentlyHidden = true;
+ hide(false /* doAnimation */, false /* requestAnim */);
+ }
+ if (isVisibleNow() && animateExit) {
mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
if (mWmService.mAccessibilityController != null) {
mWmService.mAccessibilityController.onWindowTransition(this, TRANSIT_EXIT);
@@ -2197,7 +2204,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = mChildren.get(i);
- changed |= c.onSetAppExiting();
+ changed |= c.onSetAppExiting(animateExit);
}
return changed;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index fbfa400ba852..3cbc67c004cd 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -24,6 +24,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -232,7 +233,7 @@ class WindowToken extends WindowContainer<WindowState> {
}
}
- void setExiting() {
+ void setExiting(boolean animateExit) {
if (isEmpty()) {
super.removeImmediately();
return;
@@ -247,11 +248,12 @@ class WindowToken extends WindowContainer<WindowState> {
final int count = mChildren.size();
boolean changed = false;
- final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN);
+ final boolean delayed = isAnimating(TRANSITION | PARENTS)
+ || (isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION) && animateExit);
for (int i = 0; i < count; i++) {
final WindowState win = mChildren.get(i);
- changed |= win.onSetAppExiting();
+ changed |= win.onSetAppExiting(animateExit);
}
final ActivityRecord app = asActivityRecord();
@@ -353,7 +355,7 @@ class WindowToken extends WindowContainer<WindowState> {
@Override
void removeImmediately() {
if (mDisplayContent != null) {
- mDisplayContent.removeWindowToken(token);
+ mDisplayContent.removeWindowToken(token, true /* animateExit */);
}
// Needs to occur after the token is removed from the display above to avoid attempt at
// duplicate removal of this window container from it's parent.
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 293e862a6b74..6f04f176afd8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -39,6 +39,7 @@ import static android.os.Process.NOBODY_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -2816,6 +2817,73 @@ public class ActivityRecordTests extends WindowTestsBase {
assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
}
+ @Test
+ public void testImeInsetsFrozenFlag_resetWhenReparented() {
+ final ActivityRecord activity = createActivityWithTask();
+ final WindowState app = createWindow(null, TYPE_APPLICATION, activity, "app");
+ final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+ final Task newTask = new TaskBuilder(mSupervisor).build();
+ makeWindowVisible(app, imeWindow);
+ mDisplayContent.mInputMethodWindow = imeWindow;
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+
+ // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Expect IME insets frozen state will reset when the activity is reparent to the new task.
+ activity.setState(RESUMED, "test");
+ activity.reparent(newTask, 0 /* top */, "test");
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+ }
+
+ @UseTestDisplay(addWindows = W_INPUT_METHOD)
+ @Test
+ public void testImeInsetsFrozenFlag_resetWhenResized() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ makeWindowVisibleAndDrawn(app, mImeWindow);
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+
+ // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Expect IME insets frozen state will reset when the activity is reparent to the new task.
+ app.mActivityRecord.onResize();
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+ }
+
+ @UseTestDisplay(addWindows = W_INPUT_METHOD)
+ @Test
+ public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ makeWindowVisibleAndDrawn(app, mImeWindow);
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+
+ // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+ app.mActivityRecord.commitVisibility(false, false);
+ app.mActivityRecord.onWindowsGone();
+
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Expect IME insets frozen state will reset when the activity has no IME focusable window.
+ app.mActivityRecord.forAllWindowsUnchecked(w -> {
+ w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+ return true;
+ }, true);
+
+ app.mActivityRecord.commitVisibility(true, false);
+ app.mActivityRecord.onWindowsVisible();
+
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+ }
+
private void assertHasStartingWindow(ActivityRecord atoken) {
assertNotNull(atoken.mStartingSurface);
assertNotNull(atoken.mStartingData);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index a8e17534e6ed..8e7ba4bc3293 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -258,6 +258,7 @@ public class SystemServicesTestRule implements TestRule {
final ActivityManagerInternal amInternal = mAmService.mInternal;
spyOn(amInternal);
doNothing().when(amInternal).trimApplications();
+ doNothing().when(amInternal).scheduleAppGcs();
doNothing().when(amInternal).updateCpuStats();
doNothing().when(amInternal).updateOomAdj();
doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 92b670ed9699..d88ac256be5c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -891,6 +891,40 @@ public class WindowStateTests extends WindowTestsBase {
assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
}
+ @Test
+ public void testAdjustImeInsetsVisibilityWhenSwitchingApps() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
+ final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+ spyOn(imeWindow);
+ doReturn(true).when(imeWindow).isVisible();
+ mDisplayContent.mInputMethodWindow = imeWindow;
+
+ final InsetsStateController controller = mDisplayContent.getInsetsStateController();
+ controller.getImeSourceProvider().setWindow(imeWindow, null, null);
+
+ // Simulate app requests IME with updating all windows Insets State when IME is above app.
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+ assertTrue(mDisplayContent.shouldImeAttachedToApp());
+ controller.getImeSourceProvider().scheduleShowImePostLayout(app);
+ controller.getImeSourceProvider().getSource().setVisible(true);
+ controller.updateAboveInsetsState(imeWindow, false);
+
+ // Expect all app windows behind IME can receive IME insets visible.
+ assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+ assertTrue(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+
+ // Simulate app plays closing transition to app2.
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Verify the IME insets is visible on app, but not for app2 during app task switching.
+ assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+ assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+ }
+
@UseTestDisplay(addWindows = { W_ACTIVITY })
@Test
public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index d048f1842aa3..589f9134f227 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -44,6 +45,7 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
import java.util.function.BiFunction;
@@ -126,7 +128,7 @@ public class WindowTokenTests extends WindowTestsBase {
final WindowState window1 = createWindow(null, TYPE_TOAST, token, "window1");
final WindowState window2 = createWindow(null, TYPE_TOAST, token, "window2");
- mDisplayContent.removeWindowToken(token.token);
+ mDisplayContent.removeWindowToken(token.token, true /* animateExit */);
// Verify that the token is no longer mapped on the display
assertNull(mDisplayContent.getWindowToken(token.token));
// Verify that the token is still attached to its parent
@@ -261,4 +263,29 @@ public class WindowTokenTests extends WindowTestsBase {
assertNotNull(app.getFrozenInsetsState());
assertNull(mDisplayContent.mInputMethodWindow.getFrozenInsetsState());
}
+
+ @Test
+ public void testRemoveWindowToken_noAnimateExitWhenSet() {
+ final TestWindowToken token = createTestWindowToken(0, mDisplayContent);
+ final WindowState win = createWindow(null, TYPE_APPLICATION, token, "win");
+ makeWindowVisible(win);
+ assertTrue(win.isOnScreen());
+ spyOn(win);
+ spyOn(win.mWinAnimator);
+ spyOn(win.mToken);
+
+ // Invoking removeWindowToken with setting no window exit animation and not remove window
+ // immediately. verify the window will hide without applying exit animation.
+ mWm.removeWindowToken(win.mToken.token, false /* removeWindows */, false /* animateExit */,
+ mDisplayContent.mDisplayId);
+ verify(win).onSetAppExiting(Mockito.eq(false) /* animateExit */);
+ verify(win).hide(false /* doAnimation */, false /* requestAnim */);
+ assertFalse(win.isOnScreen());
+ verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false);
+ assertTrue(win.mToken.hasChild());
+
+ // Even though the window is being removed afterwards, it won't apply exit animation.
+ win.removeIfPossible();
+ verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false);
+ }
}