Merge "Merge SP1A.211105.004 to aosp-master - DO NOT MERGE"
This commit is contained in:
commit
982bb0f145
@ -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;
|
||||
|
@ -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>>();
|
||||
@ -7020,11 +7016,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;
|
||||
|
@ -1340,7 +1340,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);
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
@ -188,6 +191,55 @@ public class QSTileHostTest extends SysuiTestCase {
|
||||
assertEquals(2, mQSTileHost.getTiles().size());
|
||||
}
|
||||
|
||||
@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()
|
||||
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1834,6 +1834,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()
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -655,6 +655,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
/** Whether the IME is showing when transitioning away from this activity. */
|
||||
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
|
||||
@ -1357,6 +1363,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) {
|
||||
@ -4767,6 +4774,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();
|
||||
@ -5885,6 +5893,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7800,6 +7816,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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -66,8 +66,8 @@ class WallpaperWindowToken extends WindowToken {
|
||||
}
|
||||
|
||||
@Override
|
||||
void setExiting() {
|
||||
super.setExiting();
|
||||
void setExiting(boolean animateExit) {
|
||||
super.setExiting(animateExit);
|
||||
mDisplayContent.mWallpaperController.removeWallpaperToken(this);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user