Merge "Add the `testOnly` flag to test_com.android.server"
diff --git a/core/proto/android/view/imeinsetssourceconsumer.proto b/core/proto/android/view/imeinsetssourceconsumer.proto
index 1b9aff9..b1ed365 100644
--- a/core/proto/android/view/imeinsetssourceconsumer.proto
+++ b/core/proto/android/view/imeinsetssourceconsumer.proto
@@ -16,7 +16,6 @@
syntax = "proto2";
-import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
import "frameworks/base/core/proto/android/view/insetssourceconsumer.proto";
package android.view;
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
deleted file mode 100644
index 384e02d..0000000
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/transparent"
- android:clipChildren="false"
- android:clipToPadding="false">
-
- <include
- layout="@layout/keyguard_host_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-</FrameLayout>
-
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index b28cb2f..60860ba 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -101,7 +101,10 @@
<FrameLayout android:id="@+id/keyguard_bouncer_container"
android:layout_height="0dp"
android:layout_width="match_parent"
- android:layout_weight="1" />
+ android:layout_weight="1"
+ android:background="@android:color/transparent"
+ android:clipChildren="false"
+ android:clipToPadding="false" />
</LinearLayout>
<com.android.systemui.biometrics.AuthRippleView
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java
deleted file mode 100644
index 4e375c2..0000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.view.ViewGroup;
-
-import com.android.keyguard.dagger.KeyguardBouncerScope;
-import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.util.ViewController;
-
-import javax.inject.Inject;
-/** Controller for a {@link KeyguardBouncer}'s Root view. */
-@KeyguardBouncerScope
-public class KeyguardRootViewController extends ViewController<ViewGroup> {
- @Inject
- public KeyguardRootViewController(@RootView ViewGroup view) {
- super(view);
- }
-
- public ViewGroup getView() {
- return mView;
- }
-
- @Override
- protected void onViewAttached() {
-
- }
-
- @Override
- protected void onViewDetached() {
-
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
index 5160b7e..0cbf8bc 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
@@ -16,10 +16,13 @@
package com.android.keyguard.dagger;
+import android.view.ViewGroup;
+
import com.android.keyguard.KeyguardHostViewController;
-import com.android.keyguard.KeyguardRootViewController;
+import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import dagger.BindsInstance;
import dagger.Subcomponent;
/**
@@ -31,12 +34,9 @@
/** Simple factory for {@link KeyguardBouncerComponent}. */
@Subcomponent.Factory
interface Factory {
- KeyguardBouncerComponent create();
+ KeyguardBouncerComponent create(@BindsInstance @RootView ViewGroup bouncerContainer);
}
- /** Returns a {@link KeyguardRootViewController}. */
- KeyguardRootViewController getKeyguardRootViewController();
-
/** Returns a {@link KeyguardHostViewController}. */
KeyguardHostViewController getKeyguardHostViewController();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
index 4fad9a9..b3c1158 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
@@ -20,7 +20,6 @@
import android.view.ViewGroup;
import com.android.keyguard.KeyguardHostView;
-import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardSecurityContainer;
import com.android.keyguard.KeyguardSecurityViewFlipper;
import com.android.systemui.R;
@@ -35,26 +34,16 @@
*/
@Module
public interface KeyguardBouncerModule {
- /** */
- @Provides
- @KeyguardBouncerScope
- @RootView
- static ViewGroup providesRootView(LayoutInflater layoutInflater) {
- return (ViewGroup) layoutInflater.inflate(R.layout.keyguard_bouncer, null);
- }
/** */
@Provides
@KeyguardBouncerScope
- static KeyguardMessageArea providesKeyguardMessageArea(@RootView ViewGroup viewGroup) {
- return viewGroup.findViewById(R.id.keyguard_message_area);
- }
-
- /** */
- @Provides
- @KeyguardBouncerScope
- static KeyguardHostView providesKeyguardHostView(@RootView ViewGroup rootView) {
- return rootView.findViewById(R.id.keyguard_host_view);
+ static KeyguardHostView providesKeyguardHostView(@RootView ViewGroup rootView,
+ LayoutInflater layoutInflater) {
+ KeyguardHostView hostView = (KeyguardHostView) layoutInflater.inflate(
+ R.layout.keyguard_host_view, rootView, false);
+ rootView.addView(hostView);
+ return hostView;
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 98b5dcc..bfa4a24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -634,20 +634,22 @@
Optional.ofNullable(BiometricUiEvent.FAILURE_EVENT_BY_SOURCE_TYPE.get(biometricSourceType))
.ifPresent(UI_EVENT_LOGGER::log);
- long currUptimeMillis = SystemClock.uptimeMillis();
- if (currUptimeMillis - mLastFpFailureUptimeMillis < 2000) { // attempt within 2 seconds
- mNumConsecutiveFpFailures += 1;
- } else {
- mNumConsecutiveFpFailures = 1;
- }
- mLastFpFailureUptimeMillis = currUptimeMillis;
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT
+ && mUpdateMonitor.isUdfpsSupported()) {
+ long currUptimeMillis = SystemClock.uptimeMillis();
+ if (currUptimeMillis - mLastFpFailureUptimeMillis
+ < (mStatusBarStateController.isDozing() ? 3500 : 2000)) {
+ mNumConsecutiveFpFailures += 1;
+ } else {
+ mNumConsecutiveFpFailures = 1;
+ }
+ mLastFpFailureUptimeMillis = currUptimeMillis;
- if (biometricSourceType.equals(BiometricSourceType.FINGERPRINT)
- && mUpdateMonitor.isUdfpsSupported()
- && mNumConsecutiveFpFailures >= FP_ATTEMPTS_BEFORE_SHOW_BOUNCER) {
- startWakeAndUnlock(MODE_SHOW_BOUNCER);
- UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN);
- mNumConsecutiveFpFailures = 0;
+ if (mNumConsecutiveFpFailures >= FP_ATTEMPTS_BEFORE_SHOW_BOUNCER) {
+ startWakeAndUnlock(MODE_SHOW_BOUNCER);
+ UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN);
+ mNumConsecutiveFpFailures = 0;
+ }
}
cleanup();
}
@@ -736,6 +738,11 @@
pw.println(" BiometricUnlockController:");
pw.print(" mMode="); pw.println(mMode);
pw.print(" mWakeLock="); pw.println(mWakeLock);
+ if (mUpdateMonitor.isUdfpsSupported()) {
+ pw.print(" mNumConsecutiveFpFailures="); pw.println(mNumConsecutiveFpFailures);
+ pw.print(" time since last failure=");
+ pw.println(SystemClock.uptimeMillis() - mLastFpFailureUptimeMillis);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 9647486..565b2d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -33,7 +33,6 @@
import com.android.internal.policy.SystemBarUtils;
import com.android.keyguard.KeyguardHostViewController;
-import com.android.keyguard.KeyguardRootViewController;
import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.KeyguardSecurityView;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -42,7 +41,6 @@
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.DejankUtils;
import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -105,12 +103,11 @@
private int mStatusBarHeight;
private float mExpansion = EXPANSION_HIDDEN;
- protected ViewGroup mRoot;
- private KeyguardRootViewController mRootViewController;
private boolean mShowingSoon;
private int mBouncerPromptReason;
private boolean mIsAnimatingAway;
private boolean mIsScrimmed;
+ private boolean mInitialized;
private KeyguardBouncer(Context context, ViewMediatorCallback callback,
ViewGroup container,
@@ -184,7 +181,7 @@
showPrimarySecurityScreen();
}
- if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
+ if (mContainer.getVisibility() == View.VISIBLE || mShowingSoon) {
return;
}
@@ -235,10 +232,8 @@
Log.wtf(TAG, "onFullyShown when view was null");
} else {
mKeyguardViewController.onResume();
- if (mRoot != null) {
- mRoot.announceForAccessibility(
- mKeyguardViewController.getAccessibilityTitleForCurrentMode());
- }
+ mContainer.announceForAccessibility(
+ mKeyguardViewController.getAccessibilityTitleForCurrentMode());
}
}
@@ -253,10 +248,8 @@
}
private void setVisibility(@View.Visibility int visibility) {
- if (mRoot != null) {
- mRoot.setVisibility(visibility);
- dispatchVisibilityChanged();
- }
+ mContainer.setVisibility(visibility);
+ dispatchVisibilityChanged();
}
private final Runnable mShowRunnable = new Runnable() {
@@ -337,14 +330,12 @@
mKeyguardViewController.cleanUp();
}
mIsAnimatingAway = false;
- if (mRoot != null) {
- setVisibility(View.INVISIBLE);
- if (destroyView) {
+ setVisibility(View.INVISIBLE);
+ if (destroyView) {
- // We have a ViewFlipper that unregisters a broadcast when being detached, which may
- // be slow because of AM lock contention during unlocking. We can delay it a bit.
- mHandler.postDelayed(mRemoveViewRunnable, 50);
- }
+ // We have a ViewFlipper that unregisters a broadcast when being detached, which may
+ // be slow because of AM lock contention during unlocking. We can delay it a bit.
+ mHandler.postDelayed(mRemoveViewRunnable, 50);
}
}
@@ -370,14 +361,13 @@
}
public void onScreenTurnedOff() {
- if (mKeyguardViewController != null
- && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
+ if (mKeyguardViewController != null && mContainer.getVisibility() == View.VISIBLE) {
mKeyguardViewController.onPause();
}
}
public boolean isShowing() {
- return (mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE))
+ return (mShowingSoon || mContainer.getVisibility() == View.VISIBLE)
&& mExpansion == EXPANSION_VISIBLE && !isAnimatingAway();
}
@@ -401,7 +391,7 @@
}
public void prepare() {
- boolean wasInitialized = mRoot != null;
+ boolean wasInitialized = mInitialized;
ensureView();
if (wasInitialized) {
showPrimarySecurityScreen();
@@ -461,7 +451,7 @@
// in this case we need to force the removal, otherwise we'll
// end up in an unpredictable state.
boolean forceRemoval = mHandler.hasCallbacks(mRemoveViewRunnable);
- if (mRoot == null || forceRemoval) {
+ if (!mInitialized || forceRemoval) {
inflateView();
}
}
@@ -469,28 +459,24 @@
protected void inflateView() {
removeView();
mHandler.removeCallbacks(mRemoveViewRunnable);
- KeyguardBouncerComponent component = mKeyguardBouncerComponentFactory.create();
- mRootViewController = component.getKeyguardRootViewController();
- mRootViewController.init();
- mRoot = mRootViewController.getView(); // TODO(b/166448040): Don't access root view here.
+
+ KeyguardBouncerComponent component = mKeyguardBouncerComponentFactory.create(mContainer);
mKeyguardViewController = component.getKeyguardHostViewController();
mKeyguardViewController.init();
- mContainer.addView(mRoot, mContainer.getChildCount());
mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext);
setVisibility(View.INVISIBLE);
- final WindowInsets rootInsets = mRoot.getRootWindowInsets();
+ final WindowInsets rootInsets = mContainer.getRootWindowInsets();
if (rootInsets != null) {
- mRoot.dispatchApplyWindowInsets(rootInsets);
+ mContainer.dispatchApplyWindowInsets(rootInsets);
}
+ mInitialized = true;
}
protected void removeView() {
- if (mRoot != null && mRoot.getParent() == mContainer) {
- mContainer.removeView(mRoot);
- mRoot = null;
- }
+ mContainer.removeAllViews();
+ mInitialized = false;
}
/**
@@ -577,7 +563,7 @@
private void dispatchVisibilityChanged() {
for (BouncerExpansionCallback callback : mExpansionCallbacks) {
- callback.onVisibilityChanged(mRoot.getVisibility() == View.VISIBLE);
+ callback.onVisibilityChanged(mContainer.getVisibility() == View.VISIBLE);
}
}
@@ -601,6 +587,7 @@
pw.println(" mShowingSoon: " + mShowingSoon);
pw.println(" mBouncerPromptReason: " + mBouncerPromptReason);
pw.println(" mIsAnimatingAway: " + mIsAnimatingAway);
+ pw.println(" mInitialized: " + mInitialized);
}
/** Update keyguard position based on a tapped X coordinate. */
@@ -675,7 +662,10 @@
mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
}
- public KeyguardBouncer create(@RootView ViewGroup container,
+ /**
+ * Construct a KeyguardBouncer that will exist in the given container.
+ */
+ public KeyguardBouncer create(ViewGroup container,
BouncerExpansionCallback expansionCallback) {
return new KeyguardBouncer(mContext, mCallback, container,
mDismissCallbackRegistry, mFalsingCollector, expansionCallback,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 875b7e5..316e682 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -51,7 +51,6 @@
import com.android.systemui.DejankUtils;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -87,7 +86,7 @@
public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
PanelExpansionListener, NavigationModeController.ModeChangedListener,
- KeyguardViewController, WakefulnessLifecycle.Observer {
+ KeyguardViewController {
// When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -392,17 +391,13 @@
} else {
mStatusBar.showKeyguard();
if (hideBouncerWhenShowing) {
- hideBouncer(shouldDestroyViewOnReset() /* destroyView */);
+ hideBouncer(false /* destroyView */);
mBouncer.prepare();
}
}
updateStates();
}
- protected boolean shouldDestroyViewOnReset() {
- return false;
- }
-
/**
* If applicable, shows the alternate authentication bouncer. Else, shows the input
* (pin/password/pattern) bouncer.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 4f3266d..40632a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -44,8 +44,10 @@
import com.android.systemui.statusbar.SmartReplyController;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Rule;
+import org.mockito.Mockito;
import java.io.FileInputStream;
import java.io.IOException;
@@ -120,11 +122,15 @@
TestableLooper.get(this).processAllMessages();
}
disallowTestableLooperAsMainThread();
- SystemUIFactory.cleanup();
mContext.cleanUpReceivers(this.getClass().getSimpleName());
mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName());
}
+ @AfterClass
+ public static void mockitoTearDown() {
+ Mockito.framework().clearInlineMocks();
+ }
+
/**
* Tests are run on the TestableLooper; however, there are parts of SystemUI that assert that
* the code is run from the main looper. Therefore, we allow the TestableLooper to pass these
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 9bf8775..8a38847 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -45,6 +45,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -86,6 +87,7 @@
super(mock(HeadsUpManagerLogger.class));
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
+ mHandler.removeCallbacksAndMessages(null);
mHandler = mTestHandler;
}
@@ -145,6 +147,11 @@
mAlertingNotificationManager = createAlertingNotificationManager();
}
+ @After
+ public void tearDown() {
+ mTestHandler.removeCallbacksAndMessages(null);
+ }
+
@Test
public void testShowNotification_addsEntry() {
mAlertingNotificationManager.showNotification(mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
index 2dfb9fc..429d2ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
@@ -60,6 +60,7 @@
import com.google.android.collect.Lists;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -131,6 +132,11 @@
verify(mNotifPipeline, never()).addCollectionListener(any());
}
+ @After
+ public void tearDown() {
+ mLogger.mHandler.removeCallbacksAndMessages(null);
+ }
+
@Test
public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception {
NotificationVisibility[] newlyVisibleKeys = {
@@ -281,6 +287,7 @@
mNotificationPanelLoggerFake
);
mBarService = barService;
+ mHandler.removeCallbacksAndMessages(null);
// Make this on the current thread so we can wait for it during tests.
mHandler = Handler.createAsync(Looper.myLooper());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 4d861f9..b69bd8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -60,6 +60,7 @@
import com.google.android.collect.Lists;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -132,6 +133,11 @@
verify(mNotifPipeline).addCollectionListener(any());
}
+ @After
+ public void tearDown() {
+ mLogger.mHandler.removeCallbacksAndMessages(null);
+ }
+
@Test
public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception {
NotificationVisibility[] newlyVisibleKeys = {
@@ -282,6 +288,7 @@
mNotificationPanelLoggerFake
);
mBarService = barService;
+ mHandler.removeCallbacksAndMessages(null);
// Make this on the current thread so we can wait for it during tests.
mHandler = Handler.createAsync(Looper.myLooper());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index f3eece8..e4721b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -36,6 +36,7 @@
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.graphics.drawable.Icon;
+import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.testing.TestableLooper;
@@ -139,6 +140,8 @@
mock(NotificationGroupManagerLegacy.class),
mock(ConfigurationControllerImpl.class)
);
+ mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
+ mHeadsUpManager.mHandler = new Handler(mTestLooper.getLooper());
mGroupMembershipManager.setHeadsUpManager(mHeadsUpManager);
mIconManager = new IconManager(
mock(CommonNotifCollection.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 0f419c7..e8b9c7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -41,6 +41,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
+import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@@ -115,9 +116,15 @@
mConfigurationController
);
super.setUp();
+ mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
mHeadsUpManager.mHandler = mTestHandler;
}
+ @After
+ public void tearDown() {
+ mTestHandler.removeCallbacksAndMessages(null);
+ }
+
@Test
public void testSnooze() {
mHeadsUpManager.showNotification(mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index e5f2aa7..f391eff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -43,7 +44,6 @@
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardHostViewController;
-import com.android.keyguard.KeyguardRootViewController;
import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
@@ -64,7 +64,6 @@
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import org.mockito.stubbing.Answer;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -92,13 +91,10 @@
@Mock
private KeyguardSecurityModel mKeyguardSecurityModel;
@Mock
- private KeyguardRootViewController mRootViewController;
- @Mock
- private ViewGroup mRootView;
- @Mock
private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock
private KeyguardBouncerComponent mKeyguardBouncerComponent;
+ private ViewGroup mContainer;
@Rule
public MockitoRule mRule = MockitoJUnit.rule();
private Integer mRootVisibility = View.INVISIBLE;
@@ -107,32 +103,22 @@
@Before
public void setup() {
allowTestableLooperAsMainThread();
- mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor);
- mDependency.injectMockDependency(KeyguardStateController.class);
- when(mRootView.getVisibility()).thenAnswer((Answer<Integer>) invocation -> mRootVisibility);
- doAnswer(invocation -> {
- mRootVisibility = invocation.getArgument(0);
- return null;
- }).when(mRootView).setVisibility(anyInt());
when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
.thenReturn(KeyguardSecurityModel.SecurityMode.None);
DejankUtils.setImmediate(true);
- when(mKeyguardBouncerComponentFactory.create()).thenReturn(mKeyguardBouncerComponent);
+
+ mContainer = spy(new FrameLayout(getContext()));
+ when(mKeyguardBouncerComponentFactory.create(mContainer)).thenReturn(
+ mKeyguardBouncerComponent);
when(mKeyguardBouncerComponent.getKeyguardHostViewController())
.thenReturn(mKeyguardHostViewController);
- when(mKeyguardBouncerComponent.getKeyguardRootViewController())
- .thenReturn(mRootViewController);
- when(mRootViewController.getView()).thenReturn(mRootView);
- when(mRootView.getResources()).thenReturn(mContext.getResources());
-
- final ViewGroup container = new FrameLayout(getContext());
mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback,
mDismissCallbackRegistry, mFalsingCollector,
mKeyguardStateController, mKeyguardUpdateMonitor,
mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
mKeyguardBouncerComponentFactory)
- .create(container, mExpansionCallback);
+ .create(mContainer, mExpansionCallback);
}
@Test
@@ -233,7 +219,7 @@
mBouncer.setExpansion(0);
verify(mKeyguardHostViewController).onResume();
- verify(mRootView).announceForAccessibility(any());
+ verify(mContainer).announceForAccessibility(any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index b717d28..9898b4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -51,6 +51,7 @@
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.wm.shell.bubbles.Bubbles;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -111,6 +112,11 @@
mHeadsUpManager.addListener(mGroupAlertTransferHelper);
}
+ @After
+ public void tearDown() {
+ mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
+ }
+
private void mockHasHeadsUpContentView(NotificationEntry entry,
boolean hasHeadsUpContentView) {
RowContentBindParams params = new RowContentBindParams();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 1cd9b9e..3b72f00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -148,6 +148,7 @@
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -366,6 +367,7 @@
private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
private FalsingManagerFake mFalsingManager = new FalsingManagerFake();
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+ private Handler mMainHandler;
@Before
public void setup() {
@@ -483,9 +485,11 @@
.thenReturn(true);
reset(mView);
+ mMainHandler = new Handler(Looper.getMainLooper());
+
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
- new Handler(Looper.getMainLooper()),
+ mMainHandler,
mLayoutInflater,
mFeatureFlags,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
@@ -560,6 +564,12 @@
.setHeadsUpAppearanceController(mock(HeadsUpAppearanceController.class));
}
+ @After
+ public void tearDown() {
+ mNotificationPanelViewController.cancelHeightAnimator();
+ mMainHandler.removeCallbacksAndMessages(null);
+ }
+
@Test
public void testSetPanelScrimMinFraction() {
mNotificationPanelViewController.setPanelScrimMinFraction(0.5f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index 5e852e3..d15ba26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -42,6 +42,7 @@
import com.android.systemui.statusbar.AlertingNotificationManagerTest;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -77,9 +78,15 @@
mHeadsUpManager = new TestableHeadsUpManager(mContext);
super.setUp();
+ mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
mHeadsUpManager.mHandler = mTestHandler;
}
+ @After
+ public void tearDown() {
+ mTestHandler.removeCallbacksAndMessages(null);
+ }
+
@Test
public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
doReturn(TEST_A11Y_AUTO_DISMISS_TIME).when(mAccessibilityMgr)
diff --git a/services/core/java/com/android/server/inputmethod/ImfLock.java b/services/core/java/com/android/server/inputmethod/ImfLock.java
new file mode 100644
index 0000000..612c14f
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/ImfLock.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+/**
+ * The implicit lock of this class serves as the global lock for
+ * the {@link InputMethodManagerService} and its controllers,
+ * which contain the main logic of the input method framework (IMF).
+ *
+ * <p>
+ * This lock can be used as follows in code:
+ * <pre>
+ * synchronized (ImfLock.class) {
+ * ...
+ * }
+ * </pre>
+ *
+ * <p>
+ * For annotations, you can use a similar syntax:
+ * <pre>
+ * @GuardedBy("ImfLock.class")
+ * myMethodDeclaration() {
+ * ...
+ * }
+ * </pre>
+ */
+final class ImfLock {
+ private ImfLock() {
+ // no instances
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 47e0e69..220d790 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -72,16 +72,16 @@
@NonNull private final WindowManagerInternal mWindowManagerInternal;
@NonNull private final Resources mRes;
- @GuardedBy("mMethodMap") private long mLastBindTime;
- @GuardedBy("mMethodMap") private boolean mHasConnection;
- @GuardedBy("mMethodMap") @Nullable private String mCurId;
- @GuardedBy("mMethodMap") @Nullable private String mSelectedMethodId;
- @GuardedBy("mMethodMap") @Nullable private Intent mCurIntent;
- @GuardedBy("mMethodMap") @Nullable private IInputMethod mCurMethod;
- @GuardedBy("mMethodMap") private int mCurMethodUid = Process.INVALID_UID;
- @GuardedBy("mMethodMap") private IBinder mCurToken;
- @GuardedBy("mMethodMap") private int mCurSeq;
- @GuardedBy("mMethodMap") private boolean mVisibleBound;
+ @GuardedBy("ImfLock.class") private long mLastBindTime;
+ @GuardedBy("ImfLock.class") private boolean mHasConnection;
+ @GuardedBy("ImfLock.class") @Nullable private String mCurId;
+ @GuardedBy("ImfLock.class") @Nullable private String mSelectedMethodId;
+ @GuardedBy("ImfLock.class") @Nullable private Intent mCurIntent;
+ @GuardedBy("ImfLock.class") @Nullable private IInputMethod mCurMethod;
+ @GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID;
+ @GuardedBy("ImfLock.class") private IBinder mCurToken;
+ @GuardedBy("ImfLock.class") private int mCurSeq;
+ @GuardedBy("ImfLock.class") private boolean mVisibleBound;
private boolean mSupportsStylusHw;
/**
@@ -146,7 +146,7 @@
* Time that we last initiated a bind to the input method, to determine
* if we should try to disconnect and reconnect to it.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
long getLastBindTime() {
return mLastBindTime;
}
@@ -155,7 +155,7 @@
* Set to true if our ServiceConnection is currently actively bound to
* a service (whether or not we have gotten its IBinder back yet).
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
boolean hasConnection() {
return mHasConnection;
}
@@ -168,7 +168,7 @@
*
* @see #getSelectedMethodId()
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@Nullable
String getCurId() {
return mCurId;
@@ -187,13 +187,13 @@
*
* @see #getCurId()
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@Nullable
String getSelectedMethodId() {
return mSelectedMethodId;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void setSelectedMethodId(@Nullable String selectedMethodId) {
mSelectedMethodId = selectedMethodId;
}
@@ -202,7 +202,7 @@
* The token we have made for the currently active input method, to
* identify it in the future.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
IBinder getCurToken() {
return mCurToken;
}
@@ -210,7 +210,7 @@
/**
* The Intent used to connect to the current input method.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@Nullable
Intent getCurIntent() {
return mCurIntent;
@@ -220,7 +220,7 @@
* The current binding sequence number, incremented every time there is
* a new bind performed.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
int getSequenceNumber() {
return mCurSeq;
}
@@ -229,7 +229,7 @@
* Increase the current binding sequence number by one.
* Reset to 1 on overflow.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void advanceSequenceNumber() {
mCurSeq += 1;
if (mCurSeq <= 0) {
@@ -241,7 +241,7 @@
* If non-null, this is the input method service we are currently connected
* to.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@Nullable
IInputMethod getCurMethod() {
return mCurMethod;
@@ -250,7 +250,7 @@
/**
* If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
int getCurMethodUid() {
return mCurMethodUid;
}
@@ -258,7 +258,7 @@
/**
* Indicates whether {@link #mVisibleConnection} is currently in use.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
boolean isVisibleBound() {
return mVisibleBound;
}
@@ -266,10 +266,10 @@
/**
* Used to bring IME service up to visible adjustment while it is being shown.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private final ServiceConnection mVisibleConnection = new ServiceConnection() {
@Override public void onBindingDied(ComponentName name) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (mVisibleBound) {
unbindVisibleConnection();
}
@@ -286,12 +286,12 @@
/**
* Used to bind the IME while it is not currently being shown.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private final ServiceConnection mMainConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected");
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
mCurMethod = IInputMethod.Stub.asInterface(service);
updateCurrentMethodUid();
@@ -318,7 +318,7 @@
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void updateCurrentMethodUid() {
final String curMethodPackage = mCurIntent.getComponent().getPackageName();
final int curMethodUid = mPackageManagerInternal.getPackageUid(
@@ -344,7 +344,7 @@
// refreshed when this method is called back. Running
// adb install -r <APK that implements the current IME>
// would be a good way to trigger such a situation.
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (DEBUG) {
Slog.v(TAG, "Service disconnected: " + name + " mCurIntent=" + mCurIntent);
}
@@ -361,7 +361,7 @@
}
};
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void unbindCurrentMethod() {
if (mVisibleBound) {
unbindVisibleConnection();
@@ -380,14 +380,14 @@
clearCurMethodAndSessions();
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void clearCurMethodAndSessions() {
mService.clearClientSessionsLocked();
mCurMethod = null;
mCurMethodUid = Process.INVALID_UID;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void removeCurrentToken() {
int curTokenDisplayId = mService.getCurTokenDisplayIdLocked();
@@ -400,7 +400,7 @@
mCurToken = null;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@NonNull
InputBindResult bindCurrentMethod() {
InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
@@ -438,7 +438,7 @@
return intent;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void addFreshWindowToken() {
int displayIdToShowIme = mService.getDisplayIdToShowImeLocked();
mCurToken = new Binder();
@@ -458,19 +458,19 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void unbindMainConnection() {
mContext.unbindService(mMainConnection);
mHasConnection = false;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void unbindVisibleConnection() {
mContext.unbindService(mVisibleConnection);
mVisibleBound = false;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean bindCurrentInputMethodService(ServiceConnection conn, int flags) {
if (mCurIntent == null || conn == null) {
Slog.e(TAG, "--- bind failed: service = " + mCurIntent + ", conn = " + conn);
@@ -480,14 +480,14 @@
new UserHandle(mSettings.getCurrentUserId()));
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean bindCurrentInputMethodServiceVisibleConnection() {
mVisibleBound = bindCurrentInputMethodService(mVisibleConnection,
IME_VISIBLE_BIND_FLAGS);
return mVisibleBound;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean bindCurrentInputMethodServiceMainConnection() {
mHasConnection = bindCurrentInputMethodService(mMainConnection,
mImeConnectionBindFlags);
@@ -500,7 +500,7 @@
* <p>
* Performs a rebind if no binding is achieved in {@link #TIME_TO_RECONNECT} milliseconds.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void setCurrentMethodVisible() {
if (mCurMethod != null) {
if (DEBUG) Slog.d(TAG, "setCurrentMethodVisible: mCurToken=" + mCurToken);
@@ -541,7 +541,7 @@
/**
* Remove the binding needed for the IME to be shown.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void setCurrentMethodNotVisible() {
if (mVisibleBound) {
unbindVisibleConnection();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 41d8332..c87dc89 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -303,9 +303,7 @@
@Nullable
private AudioManagerInternal mAudioManagerInternal = null;
-
- // All known input methods. mMethodMap also serves as the global
- // lock for this class.
+ // All known input methods.
final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
final InputMethodSubtypeSwitchingController mSwitchingController;
@@ -313,18 +311,18 @@
/**
* Tracks how many times {@link #mMethodMap} was updated.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private int mMethodMapUpdateCount = 0;
/**
* The display id for which the latest startInput was called.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
int getDisplayIdToShowImeLocked() {
return mDisplayIdToShowIme;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private int mDisplayIdToShowIme = INVALID_DISPLAY;
// Ongoing notification
@@ -410,7 +408,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
/**
@@ -431,13 +429,13 @@
*
* @see InputMethodBindingController#getCurId()
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@Nullable
- private String getSelectedMethodIdLocked() {
+ String getSelectedMethodIdLocked() {
return mBindingController.getSelectedMethodId();
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void setSelectedMethodIdLocked(@Nullable String selectedMethodId) {
mBindingController.setSelectedMethodId(selectedMethodId);
}
@@ -446,7 +444,7 @@
* The current binding sequence number, incremented every time there is
* a new bind performed.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private int getSequenceNumberLocked() {
return mBindingController.getSequenceNumber();
}
@@ -455,7 +453,7 @@
* Increase the current binding sequence number by one.
* Reset to 1 on overflow.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void advanceSequenceNumberLocked() {
mBindingController.advanceSequenceNumber();
}
@@ -517,7 +515,7 @@
*
* @see #getSelectedMethodIdLocked()
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@Nullable
private String getCurIdLocked() {
return mBindingController.getCurId();
@@ -537,7 +535,7 @@
* Set to true if our ServiceConnection is currently actively bound to
* a service (whether or not we have gotten its IBinder back yet).
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean hasConnectionLocked() {
return mBindingController.hasConnection();
}
@@ -570,7 +568,7 @@
/**
* The Intent used to connect to the current input method.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@Nullable
private Intent getCurIntentLocked() {
return mBindingController.getCurIntent();
@@ -580,7 +578,7 @@
* The token we have made for the currently active input method, to
* identify it in the future.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private IBinder getCurTokenLocked() {
return mBindingController.getCurToken();
}
@@ -588,23 +586,23 @@
/**
* The displayId of current active input method.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
int getCurTokenDisplayIdLocked() {
return mCurTokenDisplayId;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void setCurTokenDisplayIdLocked(int curTokenDisplayId) {
mCurTokenDisplayId = curTokenDisplayId;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private int mCurTokenDisplayId = INVALID_DISPLAY;
/**
* The host input token of the current active input method.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@Nullable
private IBinder mCurHostInputToken;
@@ -620,7 +618,7 @@
* If non-null, this is the input method service we are currently connected
* to.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@Nullable
private IInputMethod getCurMethodLocked() {
return mBindingController.getCurMethod();
@@ -629,7 +627,7 @@
/**
* If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntentLocked()}.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private int getCurMethodUidLocked() {
return mBindingController.getCurMethodUid();
}
@@ -638,7 +636,7 @@
* Time that we last initiated a bind to the input method, to determine
* if we should try to disconnect and reconnect to it.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private long getLastBindTimeLocked() {
return mBindingController.getLastBindTime();
}
@@ -765,7 +763,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
private static final class SoftInputShowHideHistory {
@@ -873,7 +871,7 @@
* {@link InputMethodManager#showSoftInput(View, int)}.
* This map tracks origin of showSoftInput requests.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private final WeakHashMap<IBinder, IBinder> mShowRequestWindowMap = new WeakHashMap<>();
/**
@@ -881,7 +879,7 @@
* {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}.
* This map tracks origin of hideSoftInput requests.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private final WeakHashMap<IBinder, IBinder> mHideRequestWindowMap = new WeakHashMap<>();
/**
@@ -1038,11 +1036,11 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@NonNull
private final StartInputHistory mStartInputHistory = new StartInputHistory();
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@NonNull
private final SoftInputShowHideHistory mSoftInputShowHideHistory =
new SoftInputShowHideHistory();
@@ -1060,7 +1058,7 @@
super(handler);
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
public void registerContentObserverLocked(@UserIdInt int userId) {
if (mRegistered && mUserId == userId) {
return;
@@ -1092,7 +1090,7 @@
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (showImeUri.equals(uri)) {
mMenuController.updateKeyboardFromSettingsLocked();
} else if (accessibilityRequestingNoImeUri.equals(uri)) {
@@ -1198,7 +1196,7 @@
* <p>Caution: This method must not be called when system is not ready.</p>
*/
void onActionLocaleChanged() {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales();
if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) {
return;
@@ -1220,7 +1218,7 @@
* dynamically unless the entire package is updated, which also always triggers package
* rescanning.</p>
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
/**
@@ -1243,17 +1241,17 @@
*/
private boolean mImePackageAppeared = false;
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void clearKnownImePackageNamesLocked() {
mKnownImePackageNames.clear();
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
final void addKnownImePackageNameLocked(@NonNull String packageName) {
mKnownImePackageNames.add(packageName);
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean isChangingPackagesOfCurrentUserLocked() {
final int userId = getChangingUserId();
final boolean retval = userId == mSettings.getCurrentUserId();
@@ -1267,7 +1265,7 @@
@Override
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!isChangingPackagesOfCurrentUserLocked()) {
return false;
}
@@ -1355,7 +1353,7 @@
mImePackageAppeared = false;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean shouldRebuildInputMethodListLocked() {
// This method is guaranteed to be called only by getRegisteredHandler().
@@ -1379,7 +1377,7 @@
}
private void onFinishPackageChangesInternal() {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!isChangingPackagesOfCurrentUserLocked()) {
return;
}
@@ -1502,7 +1500,7 @@
@Override
public void run() {
- synchronized (mService.mMethodMap) {
+ synchronized (ImfLock.class) {
if (mService.mUserSwitchHandlerTask != this) {
// This task was already canceled before it is handled here. So do nothing.
return;
@@ -1519,7 +1517,7 @@
* a handler callback. This needs to be set and unset only within the lock.
*/
@Nullable
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private UserSwitchHandlerTask mUserSwitchHandlerTask;
public static final class Lifecycle extends SystemService {
@@ -1541,7 +1539,7 @@
@Override
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
// Called on ActivityManager thread.
- synchronized (mService.mMethodMap) {
+ synchronized (ImfLock.class) {
mService.scheduleSwitchUserTaskLocked(to.getUserIdentifier(),
/* clientToBeReset= */ null);
}
@@ -1567,7 +1565,7 @@
}
void onUnlockUser(@UserIdInt int userId) {
- synchronized(mMethodMap) {
+ synchronized (ImfLock.class) {
final int currentUserId = mSettings.getCurrentUserId();
if (DEBUG) {
Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
@@ -1584,7 +1582,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void scheduleSwitchUserTaskLocked(@UserIdInt int userId,
@Nullable IInputMethodClient clientToBeReset) {
if (mUserSwitchHandlerTask != null) {
@@ -1677,7 +1675,7 @@
com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void resetDefaultImeLocked(Context context) {
// Do not reset the default (current) IME when it is a 3rd-party IME
String selectedMethodId = getSelectedMethodIdLocked();
@@ -1697,7 +1695,7 @@
setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void switchUserOnHandlerLocked(@UserIdInt int newUserId,
IInputMethodClient clientToBeReset) {
if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
@@ -1783,7 +1781,7 @@
}
public void systemRunning(StatusBarManagerService statusBar) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (DEBUG) {
Slog.d(TAG, "--- systemReady");
}
@@ -1839,7 +1837,7 @@
// Check whether or not this is a valid IPC. Assumes an IPC is valid when either
// 1) it comes from the system process
// 2) the calling process' user id is identical to the current user id IMMS thinks.
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean calledFromValidUserLocked() {
final int uid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(uid);
@@ -1883,7 +1881,7 @@
* @param token The window token given to the input method when it was started.
* @return true if and only if non-null valid token is specified.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
if (token == null) {
throw new InvalidParameterException("token must not be null.");
@@ -1902,7 +1900,7 @@
mContext.enforceCallingPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
mSettings.getCurrentUserId(), null);
if (resolvedUserIds.length != 1) {
@@ -1934,7 +1932,7 @@
mContext.enforceCallingPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
mSettings.getCurrentUserId(), null);
if (resolvedUserIds.length != 1) {
@@ -1949,7 +1947,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId,
@DirectBootAwareness int directBootAwareness) {
final ArrayList<InputMethodInfo> methodList;
@@ -1969,7 +1967,7 @@
return methodList;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
if (userId == mSettings.getCurrentUserId()) {
return mSettings.getEnabledInputMethodListLocked();
@@ -1980,7 +1978,7 @@
return settings.getEnabledInputMethodListLocked();
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) {
final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
@@ -2088,7 +2086,7 @@
* @param hostInputToken the host input token of the current active input method
*/
void setCurHostInputToken(@NonNull IBinder callerImeToken, @Nullable IBinder hostInputToken) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(callerImeToken)) {
return;
}
@@ -2107,7 +2105,7 @@
public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
boolean allowsImplicitlySelectedSubtypes) {
final int callingUserId = UserHandle.getCallingUserId();
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
mSettings.getCurrentUserId(), null);
if (resolvedUserIds.length != 1) {
@@ -2123,7 +2121,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
if (userId == mSettings.getCurrentUserId()) {
@@ -2178,7 +2176,7 @@
// actually running.
final int callerUid = Binder.getCallingUid();
final int callerPid = Binder.getCallingPid();
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
// TODO: Optimize this linear search.
final int numClients = mClients.size();
for (int i = 0; i < numClients; ++i) {
@@ -2211,7 +2209,7 @@
}
void removeClient(IInputMethodClient client) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
ClientState cs = mClients.remove(client.asBinder());
if (cs != null) {
client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
@@ -2245,7 +2243,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
if (mCurClient != null) {
if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client="
@@ -2271,13 +2269,13 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void clearInputShowRequestLocked() {
mShowRequested = mInputShown;
mInputShown = false;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private int getImeShowFlagsLocked() {
int flags = 0;
if (mShowForced) {
@@ -2289,7 +2287,7 @@
return flags;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private int getAppShowFlagsLocked() {
int flags = 0;
if (mShowForced) {
@@ -2300,7 +2298,7 @@
return flags;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@NonNull
InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
if (!mBoundToMethod) {
@@ -2350,7 +2348,7 @@
curId, getSequenceNumberLocked(), suppressesSpellChecker);
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@NonNull
InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
@NonNull EditorInfo attribute, @StartInputFlags int startInputFlags,
@@ -2437,14 +2435,14 @@
return mBindingController.bindCurrentMethod();
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean isSelectedMethodBoundLocked() {
String curId = getCurIdLocked();
return curId != null && curId.equals(getSelectedMethodIdLocked())
&& mDisplayIdToShowIme == mCurTokenDisplayId;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void prepareClientSwitchLocked(ClientState cs) {
// If the client is changing, we need to switch over to the new
// one.
@@ -2456,7 +2454,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@Nullable
private InputBindResult tryReuseConnectionLocked(@NonNull ClientState cs) {
if (hasConnectionLocked()) {
@@ -2529,7 +2527,7 @@
void onSessionCreated(IInputMethod method, IInputMethodSession session,
InputChannel channel) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (mUserSwitchHandlerTask != null) {
// We have a pending user-switching task so it's better to just ignore this session.
channel.dispose();
@@ -2557,7 +2555,7 @@
channel.dispose();
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void resetSystemUiLocked() {
// Set IME window status as invisible when unbinding current method.
mImeWindowVis = 0;
@@ -2567,14 +2565,14 @@
mCurHostInputToken = null;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) {
setSelectedMethodIdLocked(null);
mBindingController.unbindCurrentMethod();
unbindCurrentClientLocked(unbindClientReason);
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void reRequestCurrentClientSessionLocked() {
if (mCurClient != null) {
clearClientSessionLocked(mCurClient);
@@ -2582,7 +2580,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void requestClientSessionLocked(ClientState cs) {
if (!cs.sessionRequested) {
if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
@@ -2595,14 +2593,14 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void clearClientSessionLocked(ClientState cs) {
finishSessionLocked(cs.curSession);
cs.curSession = null;
cs.sessionRequested = false;
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void finishSessionLocked(SessionState sessionState) {
if (sessionState != null) {
if (sessionState.session != null) {
@@ -2621,7 +2619,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void clearClientSessionsLocked() {
if (getCurMethodLocked() != null) {
final int numClients = mClients.size();
@@ -2640,7 +2638,7 @@
@BinderThread
private void updateStatusIcon(@NonNull IBinder token, String packageName,
@DrawableRes int iconId) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return;
}
@@ -2674,14 +2672,14 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void hideStatusBarIconLocked() {
if (mStatusBar != null) {
mStatusBar.setIconVisibility(mSlotIme, false);
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean shouldShowImeSwitcherLocked(int visibility) {
if (!mShowOngoingImeSwitcherForPhones) return false;
if (mMenuController.getSwitchingDialogLocked() != null) return false;
@@ -2750,7 +2748,7 @@
private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return;
}
@@ -2785,7 +2783,7 @@
@BinderThread
private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return;
}
@@ -2798,7 +2796,7 @@
}
private void updateImeWindowStatus(boolean disableImeIcon) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (disableImeIcon) {
updateSystemUiLocked(0, mBackDisposition);
} else {
@@ -2807,13 +2805,13 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void updateSystemUiLocked() {
updateSystemUiLocked(mImeWindowVis, mBackDisposition);
}
// Caution! This method is called in this class. Handle multi-user carefully
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void updateSystemUiLocked(int vis, int backDisposition) {
if (getCurTokenLocked() == null) {
return;
@@ -2882,13 +2880,13 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void updateFromSettingsLocked(boolean enabledMayChange) {
updateInputMethodsFromSettingsLocked(enabledMayChange);
mMenuController.updateKeyboardFromSettingsLocked();
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
if (enabledMayChange) {
List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
@@ -2943,7 +2941,7 @@
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void setInputMethodLocked(String id, int subtypeId) {
InputMethodInfo info = mMethodMap.get(id);
if (info == null) {
@@ -3015,7 +3013,7 @@
int uid = Binder.getCallingUid();
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#showSoftInput");
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledFromValidUserLocked()) {
return false;
}
@@ -3051,7 +3049,7 @@
public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) {
Objects.requireNonNull(windowToken, "windowToken must not be null");
int uid = Binder.getCallingUid();
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledFromValidUserLocked()) {
return;
}
@@ -3068,7 +3066,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
boolean showCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
mShowRequested = true;
@@ -3109,7 +3107,7 @@
int uid = Binder.getCallingUid();
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#hideSoftInput");
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!InputMethodManagerService.this.calledFromValidUserLocked()) {
return false;
}
@@ -3146,7 +3144,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
@@ -3240,7 +3238,7 @@
userId = callingUserId;
}
final InputBindResult result;
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final long ident = Binder.clearCallingIdentity();
try {
result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
@@ -3265,7 +3263,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
@NonNull
private InputBindResult startInputOrWindowGainedFocusInternalLocked(
@StartInputReason int startInputReason, IInputMethodClient client,
@@ -3538,7 +3536,7 @@
return mWindowManagerInternal.shouldRestoreImeVisibility(windowToken);
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
// TODO(yukawa): multi-display support.
final int uid = Binder.getCallingUid();
@@ -3557,7 +3555,7 @@
@Override
public void showInputMethodPickerFromClient(IInputMethodClient client,
int auxiliarySubtypeMode) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledFromValidUserLocked()) {
return;
}
@@ -3594,14 +3592,14 @@
* A test API for CTS to make sure that the input method menu is showing.
*/
public boolean isInputMethodPickerShownForTest() {
- synchronized(mMethodMap) {
+ synchronized (ImfLock.class) {
return mMenuController.isisInputMethodPickerShownForTestLocked();
}
}
@BinderThread
private void setInputMethod(@NonNull IBinder token, String id) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return;
}
@@ -3612,7 +3610,7 @@
@BinderThread
private void setInputMethodAndSubtype(@NonNull IBinder token, String id,
InputMethodSubtype subtype) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return;
}
@@ -3629,7 +3627,7 @@
@Override
public void showInputMethodAndSubtypeEnablerFromClient(
IInputMethodClient client, String inputMethodId) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
// TODO(yukawa): Should we verify the display ID?
if (!calledFromValidUserLocked()) {
return;
@@ -3641,7 +3639,7 @@
@BinderThread
private boolean switchToPreviousInputMethod(@NonNull IBinder token) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return false;
}
@@ -3713,7 +3711,7 @@
@BinderThread
private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return false;
}
@@ -3730,7 +3728,7 @@
@BinderThread
private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return false;
}
@@ -3746,7 +3744,7 @@
@Override
public InputMethodSubtype getLastInputMethodSubtype() {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledFromValidUserLocked()) {
return null;
}
@@ -3784,7 +3782,7 @@
+ subtype.getLocale() + ", " + subtype.getMode());
}
}
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledFromValidUserLocked()) {
return;
}
@@ -3835,7 +3833,11 @@
@Override
public int getInputMethodWindowVisibleHeight() {
// TODO(yukawa): Should we verify the display ID?
- return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
+ final int curTokenDisplayId;
+ synchronized (ImfLock.class) {
+ curTokenDisplayId = mCurTokenDisplayId;
+ }
+ return mWindowManagerInternal.getInputMethodWindowVisibleHeight(curTokenDisplayId);
}
@Override
@@ -3914,7 +3916,7 @@
public void startImeTrace() {
ImeTracing.getInstance().startTrace(null /* printwriter */);
ArrayMap<IBinder, ClientState> clients;
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
clients = new ArrayMap<>(mClients);
}
for (ClientState state : clients.values()) {
@@ -3933,7 +3935,7 @@
public void stopImeTrace() {
ImeTracing.getInstance().stopTrace(null /* printwriter */);
ArrayMap<IBinder, ClientState> clients;
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
clients = new ArrayMap<>(mClients);
}
for (ClientState state : clients.values()) {
@@ -3948,7 +3950,7 @@
}
private void dumpDebug(ProtoOutputStream proto, long fieldId) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final long token = proto.start(fieldId);
proto.write(CUR_METHOD_ID, getSelectedMethodIdLocked());
proto.write(CUR_SEQ, getSequenceNumberLocked());
@@ -3989,7 +3991,7 @@
if (DEBUG) {
Slog.d(TAG, "Got the notification of a user action.");
}
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (getCurTokenLocked() != token) {
if (DEBUG) {
Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
@@ -4007,7 +4009,7 @@
@BinderThread
private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.applyImeVisibility");
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return;
}
@@ -4031,7 +4033,7 @@
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
if (token == null) {
if (mContext.checkCallingOrSelfPermission(
@@ -4056,6 +4058,7 @@
}
/** Called right after {@link IInputMethod#showSoftInput}. */
+ @GuardedBy("ImfLock.class")
private void onShowHideSoftInputRequested(boolean show, IBinder requestToken,
@SoftInputShowHideReason int reason) {
final WindowManagerInternal.ImeTargetInfo info =
@@ -4070,7 +4073,7 @@
@BinderThread
private void hideMySoftInput(@NonNull IBinder token, int flags) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return;
}
@@ -4090,7 +4093,7 @@
@BinderThread
private void showMySoftInput(@NonNull IBinder token, int flags) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showMySoftInput");
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return;
}
@@ -4188,8 +4191,11 @@
final IBinder token = (IBinder) args.arg3;
((IInputMethod) args.arg1).showSoftInput(
token, msg.arg1 /* flags */, (ResultReceiver) args.arg2);
- final IBinder requestToken = mShowRequestWindowMap.get(token);
- onShowHideSoftInputRequested(true /* show */, requestToken, reason);
+ final IBinder requestToken;
+ synchronized (ImfLock.class) {
+ requestToken = mShowRequestWindowMap.get(token);
+ onShowHideSoftInputRequested(true /* show */, requestToken, reason);
+ }
} catch (RemoteException e) {
}
args.recycle();
@@ -4204,14 +4210,17 @@
final IBinder token = (IBinder) args.arg3;
((IInputMethod)args.arg1).hideSoftInput(
token, 0 /* flags */, (ResultReceiver) args.arg2);
- final IBinder requestToken = mHideRequestWindowMap.get(token);
- onShowHideSoftInputRequested(false /* show */, requestToken, reason);
+ final IBinder requestToken;
+ synchronized (ImfLock.class) {
+ requestToken = mHideRequestWindowMap.get(token);
+ onShowHideSoftInputRequested(false /* show */, requestToken, reason);
+ }
} catch (RemoteException e) {
}
args.recycle();
return true;
case MSG_HIDE_CURRENT_INPUT_METHOD:
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final @SoftInputShowHideReason int reason = (int) msg.obj;
hideCurrentInputLocked(mCurFocusedWindow, 0, null, reason);
@@ -4221,8 +4230,10 @@
args = (SomeArgs)msg.obj;
try {
if (DEBUG) {
- Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
- + mCurTokenDisplayId);
+ synchronized (ImfLock.class) {
+ Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
+ + mCurTokenDisplayId);
+ }
}
final IBinder token = (IBinder) args.arg2;
((IInputMethod) args.arg1).initializeInternal(token,
@@ -4249,7 +4260,7 @@
return true;
}
case MSG_REMOVE_IME_SURFACE: {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
try {
if (mEnabledSession != null && mEnabledSession.session != null
&& !mShowRequested) {
@@ -4262,7 +4273,7 @@
}
case MSG_REMOVE_IME_SURFACE_FROM_WINDOW: {
IBinder windowToken = (IBinder) msg.obj;
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
try {
if (windowToken == mCurFocusedWindow
&& mEnabledSession != null && mEnabledSession.session != null) {
@@ -4404,7 +4415,7 @@
}
private void handleSetInteractive(final boolean interactive) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
mIsInteractive = interactive;
updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
@@ -4428,7 +4439,7 @@
active ? 1 : 0, fullscreen ? 1 : 0, reportToImeController ? 1 : 0, 0, state));
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean chooseNewDefaultIMELocked() {
final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
mSettings.getEnabledInputMethodListLocked());
@@ -4504,7 +4515,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
if (DEBUG) {
Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
@@ -4612,7 +4623,7 @@
mSettings.getCurrentUserId(), 0 /* unused */, inputMethodList).sendToTarget();
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void updateDefaultVoiceImeIfNeededLocked() {
final String systemSpeechRecognizer =
mContext.getString(com.android.internal.R.string.config_systemSpeechRecognizer);
@@ -4654,7 +4665,7 @@
intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
}
final int userId;
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
userId = mSettings.getCurrentUserId();
}
mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
@@ -4678,7 +4689,7 @@
* @param enabled {@code true} if {@code id} needs to be enabled.
* @return {@code true} if the IME was previously enabled. {@code false} otherwise.
*/
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
.getEnabledInputMethodsAndSubtypeListLocked();
@@ -4714,7 +4725,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
boolean setSubtypeOnly) {
mSettings.saveCurrentInputMethodAndSubtypeToHistory(getSelectedMethodIdLocked(),
@@ -4742,7 +4753,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
InputMethodInfo imi = mMethodMap.get(newDefaultIme);
int lastSubtypeId = NOT_A_SUBTYPE_ID;
@@ -4766,7 +4777,7 @@
*/
@Override
public InputMethodSubtype getCurrentInputMethodSubtype() {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
// TODO: Make this work even for non-current users?
if (!calledFromValidUserLocked()) {
return null;
@@ -4775,7 +4786,7 @@
}
}
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
String selectedMethodId = getSelectedMethodIdLocked();
if (selectedMethodId == null) {
@@ -4816,19 +4827,14 @@
return mCurrentSubtype;
}
- @Nullable
- String getCurrentMethodId() {
- return getSelectedMethodIdLocked();
- }
-
private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
return getInputMethodListLocked(userId, DirectBootAwareness.AUTO);
}
}
private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
return getEnabledInputMethodListLocked(userId);
}
}
@@ -4836,7 +4842,7 @@
private void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
InlineSuggestionsRequestInfo requestInfo,
IInlineSuggestionsRequestCallback callback) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
onCreateInlineSuggestionsRequestLocked(userId, requestInfo, callback);
}
}
@@ -4853,7 +4859,7 @@
}
private boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (userId == mSettings.getCurrentUserId()) {
if (!mMethodMap.containsKey(imeId)
|| !mSettings.getEnabledInputMethodListLocked()
@@ -4879,7 +4885,7 @@
}
private boolean setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (userId == mSettings.getCurrentUserId()) {
if (!mMethodMap.containsKey(imeId)) {
return false; // IME is not found.
@@ -4911,7 +4917,7 @@
int displayId) {
//TODO(b/150843766): Check if Input Token is valid.
final IBinder curHostInputToken;
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (displayId != mCurTokenDisplayId || mCurHostInputToken == null) {
return false;
}
@@ -4921,7 +4927,7 @@
}
private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (mCurFocusedWindow != windowToken) {
// mCurPerceptible was set by the focused window, but it is no longer in control,
// so we reset mCurPerceptible.
@@ -5029,7 +5035,7 @@
throw new InvalidParameterException("contentUri must have content scheme");
}
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final int uid = Binder.getCallingUid();
if (getSelectedMethodIdLocked() == null) {
return null;
@@ -5068,7 +5074,7 @@
@BinderThread
private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
return;
}
@@ -5151,7 +5157,7 @@
final Printer p = new PrintWriterPrinter(pw);
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
p.println("Current Input Method Manager state:");
int N = mMethodList.size();
p.println(" Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
@@ -5436,7 +5442,7 @@
@BinderThread
@ShellCommandResult
private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
return ShellCommandResult.SUCCESS;
}
@@ -5471,7 +5477,7 @@
break;
}
}
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final PrintWriter pr = shellCommand.getOutPrintWriter();
final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
@@ -5513,7 +5519,7 @@
final PrintWriter out = shellCommand.getOutPrintWriter();
final PrintWriter error = shellCommand.getErrPrintWriter();
boolean hasFailed = false;
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
for (int userId : userIds) {
@@ -5567,7 +5573,7 @@
* @return {@code false} if it fails to enable the IME. {@code false} otherwise.
*/
@BinderThread
- @GuardedBy("mMethodMap")
+ @GuardedBy("ImfLock.class")
private boolean handleShellCommandEnableDisableInputMethodInternalLocked(
@UserIdInt int userId, String imeId, boolean enabled, PrintWriter out,
PrintWriter error) {
@@ -5637,7 +5643,7 @@
final PrintWriter out = shellCommand.getOutPrintWriter();
final PrintWriter error = shellCommand.getErrPrintWriter();
boolean hasFailed = false;
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
for (int userId : userIds) {
@@ -5675,7 +5681,7 @@
private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
final PrintWriter out = shellCommand.getOutPrintWriter();
final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
for (int userId : userIds) {
@@ -5693,11 +5699,15 @@
// Also reset the settings of the current IME
mSettings.putSelectedInputMethod(null);
// Disable all enabled IMEs.
- mSettings.getEnabledInputMethodListLocked().forEach(
- imi -> setInputMethodEnabledLocked(imi.getId(), false));
+ for (InputMethodInfo inputMethodInfo :
+ mSettings.getEnabledInputMethodListLocked()) {
+ setInputMethodEnabledLocked(inputMethodInfo.getId(), false);
+ }
// Re-enable with default enabled IMEs.
- InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
- imi -> setInputMethodEnabledLocked(imi.getId(), true));
+ for (InputMethodInfo imi :
+ InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList)) {
+ setInputMethodEnabledLocked(imi.getId(), true);
+ }
updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
mSettings.getEnabledInputMethodListLocked(),
@@ -5766,7 +5776,7 @@
}
boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
ArrayMap<IBinder, ClientState> clients;
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
clients = new ArrayMap<>(mClients);
}
for (ClientState state : clients.values()) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index f70ad05..132be7d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -46,6 +46,7 @@
import android.widget.Switch;
import android.widget.TextView;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
@@ -98,7 +99,7 @@
int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
final List<ImeSubtypeListItem> imList = mSwitchingController
.getSortedInputMethodAndSubtypeListForImeMenuLocked(
showAuxSubtypes, isScreenLocked);
@@ -112,7 +113,7 @@
final InputMethodSubtype currentSubtype =
mService.getCurrentInputMethodSubtypeLocked();
if (currentSubtype != null) {
- final String curMethodId = mService.getCurrentMethodId();
+ final String curMethodId = mService.getSelectedMethodIdLocked();
final InputMethodInfo currentImi = mMethodMap.get(curMethodId);
lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
currentImi, currentSubtype.hashCode());
@@ -175,7 +176,7 @@
final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
final DialogInterface.OnClickListener choiceListener = (dialog, which) -> {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (mIms == null || mIms.length <= which || mSubtypeIds == null
|| mSubtypeIds.length <= which) {
return;
@@ -250,11 +251,12 @@
}
void hideInputMethodMenu() {
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
hideInputMethodMenuLocked();
}
}
+ @GuardedBy("ImfLock.class")
void hideInputMethodMenuLocked() {
if (DEBUG) Slog.v(TAG, "Hide switching menu");
@@ -299,7 +301,7 @@
if (DEBUG) {
Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
}
- synchronized (mMethodMap) {
+ synchronized (ImfLock.class) {
if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
&& mSwitchingDialog.isShowing()) {
mSwitchingDialogTitleView.findViewById(
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index c340a2b..f8894c6 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -39,7 +39,7 @@
* InputMethodSubtypeSwitchingController controls the switching behavior of the subtypes.
*
* <p>This class is designed to be used from and only from {@link InputMethodManagerService} by
- * using {@link InputMethodManagerService#mMethodMap} as a global lock.</p>
+ * using {@link ImfLock ImfLock.class} as a global lock.</p>
*/
final class InputMethodSubtypeSwitchingController {
private static final String TAG = InputMethodSubtypeSwitchingController.class.getSimpleName();
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 771bf19..1ba32ac 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -245,38 +245,19 @@
intent.putExtra(KEY_LOCATIONS, locationResult.asList().toArray(new Location[0]));
}
- PendingIntent.OnFinished onFinished = null;
-
- // send() SHOULD only run the completion callback if it completes successfully. however,
- // b/201299281 (which could not be fixed in the S timeframe) means that it's possible
- // for send() to throw an exception AND run the completion callback. if this happens, we
- // would over-release the wakelock... we take matters into our own hands to ensure that
- // the completion callback can only be run if send() completes successfully. this means
- // the completion callback may be run inline - but as we've never specified what thread
- // the callback is run on, this is fine.
- GatedCallback gatedCallback;
+ Runnable callback = null;
if (onCompleteCallback != null) {
- gatedCallback = new GatedCallback(() -> {
+ callback = () -> {
try {
onCompleteCallback.sendResult(null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- });
- onFinished = (pI, i, rC, rD, rE) -> gatedCallback.run();
- } else {
- gatedCallback = new GatedCallback(null);
+ };
}
- mPendingIntent.send(
- mContext,
- 0,
- intent,
- onFinished,
- null,
- null,
+ PendingIntentSender.send(mPendingIntent, mContext, intent, callback,
options.toBundle());
- gatedCallback.allow();
}
@Override
@@ -1783,12 +1764,26 @@
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
CancellationSignal.fromTransport(cancelTransport)
- .setOnCancelListener(SingleUseCallback.wrap(
+ .setOnCancelListener(
() -> {
- synchronized (mLock) {
- removeRegistration(callback.asBinder(), registration);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ removeRegistration(callback.asBinder(), registration);
+ }
+ } catch (RuntimeException e) {
+ // since this is within a oneway binder transaction there is nowhere
+ // for exceptions to go - move onto another thread to crash system
+ // server so we find out about it
+ FgThread.getExecutor().execute(() -> {
+ throw new AssertionError(e);
+ });
+ throw e;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- }));
+
+ });
return cancelTransport;
}
@@ -2733,103 +2728,84 @@
}
}
- private static class SingleUseCallback extends IRemoteCallback.Stub implements Runnable,
- CancellationSignal.OnCancelListener {
+ private static class PendingIntentSender {
- public static @Nullable SingleUseCallback wrap(@Nullable Runnable callback) {
- return callback == null ? null : new SingleUseCallback(callback);
- }
-
- @GuardedBy("this")
- private @Nullable Runnable mCallback;
-
- private SingleUseCallback(Runnable callback) {
- mCallback = Objects.requireNonNull(callback);
- }
-
- @Override
- public void sendResult(Bundle data) {
- run();
- }
-
- @Override
- public void onCancel() {
- run();
- }
-
- @Override
- public void run() {
- Runnable callback;
- synchronized (this) {
- callback = mCallback;
- mCallback = null;
+ // send() SHOULD only run the OnFinished callback if it completes successfully. however,
+ // b/201299281 (which could not be fixed in the S timeframe) means that it's possible
+ // for send() to throw an exception AND run the completion callback which breaks the
+ // guarantee we rely on. we take matters into our own hands to ensure that the OnFinished
+ // callback can only be run if send() completes successfully. this means the OnFinished
+ // callback may be run inline, so there is no longer any guarantee about what thread the
+ // callback will be run on.
+ public static void send(PendingIntent pendingIntent, Context context, Intent intent,
+ @Nullable final Runnable callback, Bundle options)
+ throws PendingIntent.CanceledException {
+ GatedCallback gatedCallback;
+ PendingIntent.OnFinished onFinished;
+ if (callback != null) {
+ gatedCallback = new GatedCallback(callback);
+ onFinished = (pI, i, rC, rD, rE) -> gatedCallback.run();
+ } else {
+ gatedCallback = null;
+ onFinished = null;
}
- // prevent this callback from being run more than once - otherwise this could provide an
- // attack vector for a malicious app to break assumptions on how many times a callback
- // may be invoked, and thus crash system server.
- if (callback == null) {
- return;
- }
-
- final long identity = Binder.clearCallingIdentity();
- try {
- callback.run();
- } catch (RuntimeException e) {
- // since this is within a oneway binder transaction there is nowhere
- // for exceptions to go - move onto another thread to crash system
- // server so we find out about it
- FgThread.getExecutor().execute(() -> {
- throw new AssertionError(e);
- });
- throw e;
- } finally {
- Binder.restoreCallingIdentity(identity);
+ pendingIntent.send(
+ context,
+ 0,
+ intent,
+ onFinished,
+ null,
+ null,
+ options);
+ if (gatedCallback != null) {
+ gatedCallback.allow();
}
}
- }
- private static class GatedCallback implements Runnable {
+ private static class GatedCallback implements Runnable {
- private @Nullable Runnable mCallback;
+ @GuardedBy("this")
+ private @Nullable Runnable mCallback;
- @GuardedBy("this")
- private boolean mGate;
- @GuardedBy("this")
- private boolean mRun;
+ @GuardedBy("this")
+ private boolean mGate;
+ @GuardedBy("this")
+ private boolean mRun;
- GatedCallback(@Nullable Runnable callback) {
- mCallback = callback;
- }
+ private GatedCallback(@Nullable Runnable callback) {
+ mCallback = callback;
+ }
- public void allow() {
- Runnable callback = null;
- synchronized (this) {
- mGate = true;
- if (mRun && mCallback != null) {
- callback = mCallback;
- mCallback = null;
+ public void allow() {
+ Runnable callback = null;
+ synchronized (this) {
+ mGate = true;
+ if (mRun && mCallback != null) {
+ callback = mCallback;
+ mCallback = null;
+ }
+ }
+
+ if (callback != null) {
+ callback.run();
}
}
- if (callback != null) {
- callback.run();
- }
- }
-
- @Override
- public void run() {
- Runnable callback = null;
- synchronized (this) {
- mRun = true;
- if (mGate && mCallback != null) {
- callback = mCallback;
- mCallback = null;
+ @Override
+ public void run() {
+ Runnable callback = null;
+ synchronized (this) {
+ mRun = true;
+ if (mGate && mCallback != null) {
+ callback = mCallback;
+ mCallback = null;
+ }
}
- }
- if (callback != null) {
- callback.run();
+ if (callback != null) {
+ callback.run();
+ }
}
}
}
@@ -2850,7 +2826,19 @@
try {
mWakeLock.release();
} catch (RuntimeException e) {
- Log.e(TAG, "wakelock over-released by " + mIdentity, e);
+ // wakelock throws a RuntimeException instead of some more specific exception, so
+ // attempt to capture only actual RuntimeExceptions
+ if (e.getClass() == RuntimeException.class) {
+ Log.e(TAG, "wakelock over-released by " + mIdentity, e);
+ } else {
+ // since this is within a oneway binder transaction there is nowhere for
+ // exceptions to go - move onto another thread to crash system server so we find
+ // out about it
+ FgThread.getExecutor().execute(() -> {
+ throw new AssertionError(e);
+ });
+ throw e;
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}