summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/app/LocaleConfig.java4
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java17
-rw-r--r--core/java/android/content/pm/PackageParser.java18
-rw-r--r--core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java30
-rw-r--r--core/java/android/inputmethodservice/IInputMethodWrapper.java15
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java70
-rw-r--r--core/java/android/provider/DeviceConfig.java8
-rw-r--r--core/java/android/provider/Settings.java34
-rw-r--r--core/java/android/service/quickaccesswallet/TEST_MAPPING2
-rw-r--r--core/java/android/view/View.java22
-rw-r--r--core/java/android/view/ViewRootImpl.java40
-rw-r--r--core/java/android/view/inputmethod/InputMethod.java8
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java26
-rw-r--r--core/java/android/view/translation/UiTranslationController.java7
-rw-r--r--core/java/android/window/ImeOnBackInvokedDispatcher.aidl20
-rw-r--r--core/java/android/window/ImeOnBackInvokedDispatcher.java187
-rw-r--r--core/java/android/window/OnBackInvokedDispatcher.java15
-rw-r--r--core/java/android/window/ProxyOnBackInvokedDispatcher.java16
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java37
-rw-r--r--core/java/android/window/WindowTokenClient.java28
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java21
-rw-r--r--core/java/com/android/internal/app/ChooserActivityLogger.java3
-rw-r--r--core/java/com/android/internal/app/ChooserActivityLoggerImpl.java6
-rw-r--r--core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java2
-rw-r--r--core/java/com/android/internal/app/UnlaunchableAppActivity.java7
-rw-r--r--core/java/com/android/internal/logging/UiEventLoggerImpl.java6
-rw-r--r--core/java/com/android/internal/policy/DecorView.java2
-rw-r--r--core/java/com/android/internal/view/IInputMethod.aidl4
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl3
-rw-r--r--core/jni/android_media_AudioSystem.cpp39
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java10
-rw-r--r--data/etc/services.core.protolog.json18
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java46
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java145
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java6
-rw-r--r--keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java123
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java114
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java8
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java8
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_content_layout.xml2
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java3
-rw-r--r--packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java24
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java4
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java9
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java10
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java3
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java5
-rw-r--r--packages/SystemUI/res/layout/alert_dialog_systemui.xml124
-rw-r--r--packages/SystemUI/res/layout/scrollable_alert_dialog_systemui.xml25
-rw-r--r--packages/SystemUI/res/values/styles.xml7
-rw-r--r--packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt197
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java29
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconView.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt193
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java71
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java45
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java5
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java9
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java56
-rw-r--r--services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java88
-rw-r--r--services/core/java/com/android/server/am/DropboxRateLimiter.java11
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java9
-rw-r--r--services/core/java/com/android/server/audio/SpatializerHelper.java6
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java7
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java8
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingModeController.java27
-rw-r--r--services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java6
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java57
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java68
-rw-r--r--services/core/java/com/android/server/pm/ApkChecksums.java15
-rw-r--r--services/core/java/com/android/server/pm/Installer.java23
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java328
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java15
-rw-r--r--services/core/java/com/android/server/utils/WatchedArrayList.java2
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java37
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java7
-rw-r--r--services/core/java/com/android/server/wm/BLASTSyncEngine.java21
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java38
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java55
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java25
-rw-r--r--services/proguard.flags5
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java16
-rw-r--r--services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt25
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java41
-rw-r--r--telecomm/java/android/telecom/PhoneAccountHandle.java33
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java19
-rw-r--r--telephony/java/android/telephony/DataFailCause.java5
-rw-r--r--tests/ApkVerityTest/Android.bp4
-rw-r--r--tests/ApkVerityTest/block_device_writer/Android.bp24
-rw-r--r--tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java2
116 files changed, 2505 insertions, 781 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index d6a067d35f9b..2c0b6e9ee89d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -800,6 +800,7 @@ package android.content.pm {
method public boolean hasRequestForegroundServiceExemption();
method public boolean isPrivilegedApp();
method public boolean isSystemApp();
+ method public void setEnableOnBackInvokedCallback(boolean);
field public static final int PRIVATE_FLAG_PRIVILEGED = 8; // 0x8
field public int privateFlags;
}
diff --git a/core/java/android/app/LocaleConfig.java b/core/java/android/app/LocaleConfig.java
index 436eac37b4fb..7c83d5850f76 100644
--- a/core/java/android/app/LocaleConfig.java
+++ b/core/java/android/app/LocaleConfig.java
@@ -45,7 +45,9 @@ import java.util.Set;
* referenced in the manifest via {@code android:localeConfig} on
* {@code <application>}.
*
- * For more information, see TODO(b/214154050): add link to guide
+ * <p>For more information, see
+ * <a href="https://developer.android.com/about/versions/13/features/app-languages#use-localeconfig">
+ * the section on per-app language preferences</a>.
*
* @attr ref android.R.styleable#LocaleConfig_Locale_name
* @attr ref android.R.styleable#AndroidManifestApplication_localeConfig
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2961b5505794..24c383692c09 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -2752,4 +2752,21 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
mKnownActivityEmbeddingCerts.add(knownCert.toUpperCase(Locale.US));
}
}
+
+ /**
+ * Sets whether the application will use the {@link android.window.OnBackInvokedCallback}
+ * navigation system instead of the {@link android.view.KeyEvent#KEYCODE_BACK} and related
+ * callbacks. Intended to be used from tests only.
+ *
+ * @see #isOnBackInvokedCallbackEnabled()
+ * @hide
+ */
+ @TestApi
+ public void setEnableOnBackInvokedCallback(boolean isEnable) {
+ if (isEnable) {
+ privateFlagsExt |= PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
+ } else {
+ privateFlagsExt &= ~PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
+ }
+ }
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 44dc28d2b0fa..52e64e80e6d4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2618,6 +2618,15 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ targetCode)) {
+ Slog.w(TAG, "Package requires development platform " + targetCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return Build.VERSION.SDK_INT;
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + targetCode
@@ -2689,6 +2698,15 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ minCode)) {
+ Slog.w(TAG, "Package requires min development platform " + minCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return Build.VERSION.SDK_INT;
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 6d74b819301d..bde71bb90bf7 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -315,6 +315,15 @@ public class FrameworkParsingPackageUtils {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ minCode)) {
+ Slog.w(TAG, "Parsed package requires min development platform " + minCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return input.success(Build.VERSION.SDK_INT);
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -367,16 +376,29 @@ public class FrameworkParsingPackageUtils {
return input.success(targetVers);
}
- if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
- return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
- }
-
// If it's a pre-release SDK and the codename matches this platform, it
// definitely targets this SDK.
if (matchTargetCode(platformSdkCodenames, targetCode)) {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ targetCode)) {
+ Slog.w(TAG, "Parsed package requires development platform " + targetCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return input.success(Build.VERSION.SDK_INT);
+ }
+
+ try {
+ if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
+ return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+ } catch (IllegalArgumentException e) {
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index f9ed0e3db499..3f49b73a78fc 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -37,6 +37,7 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
import android.view.inputmethod.InputMethodSubtype;
+import android.window.ImeOnBackInvokedDispatcher;
import com.android.internal.inputmethod.CancellationGroup;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
@@ -194,7 +195,9 @@ class IInputMethodWrapper extends IInputMethod.Stub
case DO_START_INPUT: {
final SomeArgs args = (SomeArgs) msg.obj;
final IBinder startInputToken = (IBinder) args.arg1;
- final IInputContext inputContext = (IInputContext) args.arg2;
+ final IInputContext inputContext = (IInputContext) ((SomeArgs) args.arg2).arg1;
+ final ImeOnBackInvokedDispatcher imeDispatcher =
+ (ImeOnBackInvokedDispatcher) ((SomeArgs) args.arg2).arg2;
final EditorInfo info = (EditorInfo) args.arg3;
final CancellationGroup cancellationGroup = (CancellationGroup) args.arg4;
final boolean restarting = args.argi5 == 1;
@@ -205,7 +208,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
: null;
info.makeCompatible(mTargetSdkVersion);
inputMethod.dispatchStartInputWithToken(ic, info, restarting, startInputToken,
- navButtonFlags);
+ navButtonFlags, imeDispatcher);
args.recycle();
return;
}
@@ -348,13 +351,17 @@ class IInputMethodWrapper extends IInputMethod.Stub
@Override
public void startInput(IBinder startInputToken, IInputContext inputContext,
EditorInfo attribute, boolean restarting,
- @InputMethodNavButtonFlags int navButtonFlags) {
+ @InputMethodNavButtonFlags int navButtonFlags,
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
if (mCancellationGroup == null) {
Log.e(TAG, "startInput must be called after bindInput.");
mCancellationGroup = new CancellationGroup();
}
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = inputContext;
+ args.arg2 = imeDispatcher;
mCaller.executeOrSendMessage(mCaller.obtainMessageOOOOII(DO_START_INPUT, startInputToken,
- inputContext, attribute, mCancellationGroup, restarting ? 1 : 0, navButtonFlags));
+ args, attribute, mCancellationGroup, restarting ? 1 : 0, navButtonFlags));
}
@BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index efd4f0681838..25296bc0a8b9 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -101,6 +101,7 @@ import android.view.BatchedInputEventReceiver.SimpleBatchedInputEventReceiver;
import android.view.Choreographer;
import android.view.Gravity;
import android.view.InputChannel;
+import android.view.InputDevice;
import android.view.InputEventReceiver;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -134,6 +135,9 @@ import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
+import android.window.ImeOnBackInvokedDispatcher;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import android.window.WindowMetricsHelper;
import com.android.internal.annotations.GuardedBy;
@@ -344,6 +348,9 @@ public class InputMethodService extends AbstractInputMethodService {
* A circular buffer of size MAX_EVENTS_BUFFER in case IME is taking too long to add ink view.
**/
private RingBuffer<MotionEvent> mPendingEvents;
+ private ImeOnBackInvokedDispatcher mImeDispatcher;
+ private Boolean mBackCallbackRegistered = false;
+ private final OnBackInvokedCallback mCompatBackCallback = this::compatHandleBack;
/**
* Returns whether {@link InputMethodService} is responsible for rendering the back button and
@@ -797,7 +804,13 @@ public class InputMethodService extends AbstractInputMethodService {
@Override
public final void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
@NonNull EditorInfo editorInfo, boolean restarting,
- @NonNull IBinder startInputToken, @InputMethodNavButtonFlags int navButtonFlags) {
+ @NonNull IBinder startInputToken, @InputMethodNavButtonFlags int navButtonFlags,
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
+ mImeDispatcher = imeDispatcher;
+ if (mWindow != null) {
+ mWindow.getOnBackInvokedDispatcher().setImeOnBackInvokedDispatcher(
+ imeDispatcher);
+ }
mPrivOps.reportStartInputAsync(startInputToken);
mNavigationBarController.onNavButtonFlagsChanged(navButtonFlags);
if (restarting) {
@@ -1496,6 +1509,10 @@ public class InputMethodService extends AbstractInputMethodService {
Context.LAYOUT_INFLATER_SERVICE);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initSoftInputWindow");
mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
+ if (mImeDispatcher != null) {
+ mWindow.getOnBackInvokedDispatcher()
+ .setImeOnBackInvokedDispatcher(mImeDispatcher);
+ }
mNavigationBarController.onSoftInputWindowCreated(mWindow);
{
final Window window = mWindow.getWindow();
@@ -1608,6 +1625,8 @@ public class InputMethodService extends AbstractInputMethodService {
// when IME developers are doing something unsupported.
InputMethodPrivilegedOperationsRegistry.remove(mToken);
}
+ unregisterCompatOnBackInvokedCallback();
+ mImeDispatcher = null;
}
/**
@@ -2568,8 +2587,46 @@ public class InputMethodService extends AbstractInputMethodService {
cancelImeSurfaceRemoval();
mInShowWindow = false;
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ registerCompatOnBackInvokedCallback();
+ }
+
+
+ /**
+ * Registers an {@link OnBackInvokedCallback} to handle back invocation when ahead-of-time
+ * back dispatching is enabled. We keep the {@link KeyEvent#KEYCODE_BACK} based legacy code
+ * around to handle back on older devices.
+ */
+ private void registerCompatOnBackInvokedCallback() {
+ if (mBackCallbackRegistered) {
+ return;
+ }
+ if (mWindow != null) {
+ mWindow.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatBackCallback);
+ mBackCallbackRegistered = true;
+ }
+ }
+
+ private void unregisterCompatOnBackInvokedCallback() {
+ if (!mBackCallbackRegistered) {
+ return;
+ }
+ if (mWindow != null) {
+ mWindow.getOnBackInvokedDispatcher()
+ .unregisterOnBackInvokedCallback(mCompatBackCallback);
+ mBackCallbackRegistered = false;
+ }
}
+ private KeyEvent createBackKeyEvent(int action, boolean isTracking) {
+ final long when = SystemClock.uptimeMillis();
+ return new KeyEvent(when, when, action,
+ KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
+ KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY
+ | (isTracking ? KeyEvent.FLAG_TRACKING : 0),
+ InputDevice.SOURCE_KEYBOARD);
+ }
private boolean prepareWindow(boolean showInput) {
boolean doShowInput = false;
@@ -2658,6 +2715,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
mLastWasInFullscreenMode = mIsFullscreen;
updateFullscreenMode();
+ unregisterCompatOnBackInvokedCallback();
}
/**
@@ -3797,4 +3855,14 @@ public class InputMethodService extends AbstractInputMethodService {
proto.end(token);
}
};
+
+ private void compatHandleBack() {
+ final KeyEvent downEvent = createBackKeyEvent(
+ KeyEvent.ACTION_DOWN, false /* isTracking */);
+ onKeyDown(KeyEvent.KEYCODE_BACK, downEvent);
+ final boolean hasStartedTracking =
+ (downEvent.getFlags() & KeyEvent.FLAG_START_TRACKING) != 0;
+ final KeyEvent upEvent = createBackKeyEvent(KeyEvent.ACTION_UP, hasStartedTracking);
+ onKeyUp(KeyEvent.KEYCODE_BACK, upEvent);
+ }
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 37f44e98c165..9a2f7baa7265 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -738,6 +738,14 @@ public final class DeviceConfig {
*/
public static final String NAMESPACE_VENDOR_SYSTEM_NATIVE = "vendor_system_native";
+ /**
+ * Namespace for DevicePolicyManager related features.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_DEVICE_POLICY_MANAGER =
+ "device_policy_manager";
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index dac54cf6146e..f35a45891545 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9695,6 +9695,40 @@ public final class Settings {
"active_unlock_on_biometric_fail";
/**
+ * If active unlock triggers on biometric failures, include the following error codes
+ * as a biometric failure. See {@link android.hardware.biometrics.BiometricFaceConstants}.
+ * Error codes should be separated by a pipe. For example: "1|4|5". If active unlock
+ * should never trigger on any face errors, this should be set to an empty string.
+ * A null value will use the system default value (TIMEOUT).
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_ON_FACE_ERRORS =
+ "active_unlock_on_face_errors";
+
+ /**
+ * If active unlock triggers on biometric failures, include the following acquired info
+ * as a "biometric failure". See {@link android.hardware.biometrics.BiometricFaceConstants}.
+ * Acquired codes should be separated by a pipe. For example: "1|4|5". If active unlock
+ * should never on trigger on any acquired info messages, this should be
+ * set to an empty string. A null value will use the system default value (none).
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO =
+ "active_unlock_on_face_acquire_info";
+
+ /**
+ * If active unlock triggers on biometric failures, then also request active unlock on
+ * unlock intent when each setting (BiometricType) is the only biometric type enrolled.
+ * Biometric types should be separated by a pipe. For example: "0|3" or "0". If this
+ * setting should be disabled, then this should be set to an empty string. A null value
+ * will use the system default value (0 / None).
+ * 0 = None, 1 = Any face, 2 = Any fingerprint, 3 = Under display fingerprint
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED =
+ "active_unlock_on_unlock_intent_when_biometric_enrolled";
+
+ /**
* Whether the assist gesture should be enabled.
*
* @hide
diff --git a/core/java/android/service/quickaccesswallet/TEST_MAPPING b/core/java/android/service/quickaccesswallet/TEST_MAPPING
index 4d97ab6e612d..5d2a3a806a7b 100644
--- a/core/java/android/service/quickaccesswallet/TEST_MAPPING
+++ b/core/java/android/service/quickaccesswallet/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit": [
+ "presubmit-large": [
{
"name": "CtsQuickAccessWalletTestCases"
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2475e2cf3dd8..d04b07c13b41 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9922,7 +9922,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* <ol>
* <li>It should only be called when content capture is enabled for the view.
* <li>It must call viewAppeared() before viewDisappeared()
- * <li>viewAppearead() can only be called when the view is visible and laidout
+ * <li>viewAppeared() can only be called when the view is visible and laid out
* <li>It should not call the same event twice.
* </ol>
*/
@@ -9999,6 +9999,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this);
}
}
+
+ // We reset any translation state as views may be re-used (e.g., as in ListView and
+ // RecyclerView). We only need to do this for views important for content capture since
+ // views unimportant for content capture won't be translated anyway.
+ clearTranslationState();
}
}
@@ -12719,6 +12724,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @hide
+ */
+ public void clearTranslationState() {
+ if (mViewTranslationCallback != null) {
+ mViewTranslationCallback.onClearTranslation(this);
+ }
+ clearViewTranslationCallback();
+ clearViewTranslationResponse();
+ if (hasTranslationTransientState()) {
+ setHasTransientState(false);
+ setHasTranslationTransientState(false);
+ }
+ }
+
+ /**
* Returns true if this view is currently attached to a window.
*/
public boolean isAttachedToWindow() {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0bdbfbcf0dfc..48c102bd4883 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6095,6 +6095,28 @@ public final class ViewRootImpl implements ViewParent,
@Override
protected int onProcess(QueuedInputEvent q) {
+ if (q.mEvent instanceof KeyEvent) {
+ final KeyEvent event = (KeyEvent) q.mEvent;
+
+ // If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the
+ // view tree or IME, and invoke the appropriate {@link OnBackInvokedCallback}.
+ if (isBack(event)
+ && mContext != null
+ && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
+ OnBackInvokedCallback topCallback =
+ getOnBackInvokedDispatcher().getTopCallback();
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ if (topCallback != null) {
+ topCallback.onBackInvoked();
+ return FINISH_HANDLED;
+ }
+ } else {
+ // Drop other actions such as {@link KeyEvent.ACTION_DOWN}.
+ return FINISH_NOT_HANDLED;
+ }
+ }
+ }
+
if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
mInputQueue.sendInputEvent(q.mEvent, q, true, this);
return DEFER;
@@ -6446,24 +6468,6 @@ public final class ViewRootImpl implements ViewParent,
return FINISH_HANDLED;
}
- // If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the
- // view tree and invoke the appropriate {@link OnBackInvokedCallback}.
- if (isBack(event)
- && mContext != null
- && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
- OnBackInvokedCallback topCallback =
- getOnBackInvokedDispatcher().getTopCallback();
- if (event.getAction() == KeyEvent.ACTION_UP) {
- if (topCallback != null) {
- topCallback.onBackInvoked();
- return FINISH_HANDLED;
- }
- } else {
- // Drop other actions such as {@link KeyEvent.ACTION_DOWN}.
- return FINISH_NOT_HANDLED;
- }
- }
-
// Deliver the key to the view hierarchy.
if (mView.dispatchKeyEvent(event)) {
return FINISH_HANDLED;
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 6209b46997e8..dbdc0daff2c1 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -29,6 +29,7 @@ import android.util.Log;
import android.view.InputChannel;
import android.view.MotionEvent;
import android.view.View;
+import android.window.ImeOnBackInvokedDispatcher;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodNavButtonFlags;
@@ -232,6 +233,10 @@ public interface InputMethod {
* long as your implementation of {@link InputMethod} relies on such
* IPCs
* @param navButtonFlags {@link InputMethodNavButtonFlags} in the initial state of this session.
+ * @param imeDispatcher The {@link ImeOnBackInvokedDispatcher }} to be set on the
+ * IME's {@link android.window.WindowOnBackInvokedDispatcher}, so that IME
+ * {@link android.window.OnBackInvokedCallback}s can be forwarded to
+ * the client requesting to start input.
* @see #startInput(InputConnection, EditorInfo)
* @see #restartInput(InputConnection, EditorInfo)
* @see EditorInfo
@@ -240,7 +245,8 @@ public interface InputMethod {
@MainThread
default void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
@NonNull EditorInfo editorInfo, boolean restarting,
- @NonNull IBinder startInputToken, @InputMethodNavButtonFlags int navButtonFlags) {
+ @NonNull IBinder startInputToken, @InputMethodNavButtonFlags int navButtonFlags,
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
if (restarting) {
restartInput(inputConnection, editorInfo);
} else {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index d9bde5825fde..e2e9a8557793 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -91,6 +91,8 @@ import android.view.View;
import android.view.ViewRootImpl;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.autofill.AutofillManager;
+import android.window.ImeOnBackInvokedDispatcher;
+import android.window.WindowOnBackInvokedDispatcher;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.DirectBootAwareness;
@@ -105,6 +107,7 @@ import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
import com.android.internal.inputmethod.UnbindReason;
import com.android.internal.os.SomeArgs;
+import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
import com.android.internal.view.IInputMethodSession;
@@ -279,6 +282,21 @@ public final class InputMethodManager {
private static final String SUBTYPE_MODE_VOICE = "voice";
/**
+ * Provide this to {@link IInputMethodManager#startInputOrWindowGainedFocus(
+ * int, IInputMethodClient, IBinder, int, int, int, EditorInfo, IInputContext, int)} to receive
+ * {@link android.window.OnBackInvokedCallback} registrations from IME.
+ */
+ private final ImeOnBackInvokedDispatcher mImeDispatcher =
+ new ImeOnBackInvokedDispatcher(Handler.getMain()) {
+ @Override
+ public WindowOnBackInvokedDispatcher getReceivingDispatcher() {
+ synchronized (mH) {
+ return mCurRootView != null ? mCurRootView.getOnBackInvokedDispatcher() : null;
+ }
+ }
+ };
+
+ /**
* Ensures that {@link #sInstance} becomes non-{@code null} for application that have directly
* or indirectly relied on {@link #sInstance} via reflection or something like that.
*
@@ -740,7 +758,8 @@ public final class InputMethodManager {
windowFlags,
null,
null, null,
- mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
+ mCurRootView.mContext.getApplicationInfo().targetSdkVersion,
+ mImeDispatcher);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1687,6 +1706,8 @@ public final class InputMethodManager {
mServedConnecting = false;
clearConnectionLocked();
}
+ // Clear the back callbacks held by the ime dispatcher to avoid memory leaks.
+ mImeDispatcher.clear();
}
public void displayCompletions(View view, CompletionInfo[] completions) {
@@ -2359,7 +2380,8 @@ public final class InputMethodManager {
softInputMode, windowFlags, tba, servedInputConnection,
servedInputConnection == null ? null
: servedInputConnection.asIRemoteAccessibilityInputConnection(),
- view.getContext().getApplicationInfo().targetSdkVersion);
+ view.getContext().getApplicationInfo().targetSdkVersion,
+ mImeDispatcher);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index 8cf032bc03cb..6bf2474beb17 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -158,12 +158,7 @@ public class UiTranslationController implements Dumpable {
case STATE_UI_TRANSLATION_FINISHED:
destroyTranslators();
runForEachView((view, callback) -> {
- callback.onClearTranslation(view);
- view.clearViewTranslationResponse();
- if (view.hasTranslationTransientState()) {
- view.setHasTransientState(false);
- view.setHasTranslationTransientState(false);
- }
+ view.clearTranslationState();
});
notifyTranslationFinished(/* activityDestroyed= */ false);
synchronized (mLock) {
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.aidl b/core/java/android/window/ImeOnBackInvokedDispatcher.aidl
new file mode 100644
index 000000000000..04e64203dd39
--- /dev/null
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/os/ParcelFileDescriptor.aidl
+**
+** Copyright 2022, 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 android.window;
+
+parcelable ImeOnBackInvokedDispatcher;
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java
new file mode 100644
index 000000000000..d5763aa25884
--- /dev/null
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2022 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 android.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * A {@link OnBackInvokedDispatcher} for IME that forwards {@link OnBackInvokedCallback}
+ * registrations from the IME process to the app process to be registered on the app window.
+ * <p>
+ * The app process creates and propagates an instance of {@link ImeOnBackInvokedDispatcher}
+ * to the IME to be set on the IME window's {@link WindowOnBackInvokedDispatcher}.
+ * <p>
+ * @see WindowOnBackInvokedDispatcher#setImeOnBackInvokedDispatcher
+ *
+ * @hide
+ */
+public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parcelable {
+
+ private static final String TAG = "ImeBackDispatcher";
+ static final String RESULT_KEY_ID = "id";
+ static final String RESULT_KEY_CALLBACK = "callback";
+ static final String RESULT_KEY_PRIORITY = "priority";
+ static final int RESULT_CODE_REGISTER = 0;
+ static final int RESULT_CODE_UNREGISTER = 1;
+ @NonNull
+ private final ResultReceiver mResultReceiver;
+
+ public ImeOnBackInvokedDispatcher(Handler handler) {
+ mResultReceiver = new ResultReceiver(handler) {
+ @Override
+ public void onReceiveResult(int resultCode, Bundle resultData) {
+ WindowOnBackInvokedDispatcher dispatcher = getReceivingDispatcher();
+ if (dispatcher != null) {
+ receive(resultCode, resultData, dispatcher);
+ }
+ }
+ };
+ }
+
+ /**
+ * Override this method to return the {@link WindowOnBackInvokedDispatcher} of the window
+ * that should receive the forwarded callback.
+ */
+ @Nullable
+ protected WindowOnBackInvokedDispatcher getReceivingDispatcher() {
+ return null;
+ }
+
+ ImeOnBackInvokedDispatcher(Parcel in) {
+ mResultReceiver = in.readTypedObject(ResultReceiver.CREATOR);
+ }
+
+ @Override
+ public void registerOnBackInvokedCallback(
+ @OnBackInvokedDispatcher.Priority int priority,
+ @NonNull OnBackInvokedCallback callback) {
+ final Bundle bundle = new Bundle();
+ final IOnBackInvokedCallback iCallback =
+ new WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper(callback);
+ bundle.putBinder(RESULT_KEY_CALLBACK, iCallback.asBinder());
+ bundle.putInt(RESULT_KEY_PRIORITY, priority);
+ bundle.putInt(RESULT_KEY_ID, callback.hashCode());
+ mResultReceiver.send(RESULT_CODE_REGISTER, bundle);
+ }
+
+ @Override
+ public void unregisterOnBackInvokedCallback(
+ @NonNull OnBackInvokedCallback callback) {
+ Bundle bundle = new Bundle();
+ bundle.putInt(RESULT_KEY_ID, callback.hashCode());
+ mResultReceiver.send(RESULT_CODE_UNREGISTER, bundle);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeTypedObject(mResultReceiver, flags);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<ImeOnBackInvokedDispatcher> CREATOR =
+ new Parcelable.Creator<ImeOnBackInvokedDispatcher>() {
+ public ImeOnBackInvokedDispatcher createFromParcel(Parcel in) {
+ return new ImeOnBackInvokedDispatcher(in);
+ }
+ public ImeOnBackInvokedDispatcher[] newArray(int size) {
+ return new ImeOnBackInvokedDispatcher[size];
+ }
+ };
+
+ private final HashMap<Integer, OnBackInvokedCallback> mImeCallbackMap = new HashMap<>();
+
+ private void receive(
+ int resultCode, Bundle resultData,
+ @NonNull OnBackInvokedDispatcher receivingDispatcher) {
+ final int callbackId = resultData.getInt(RESULT_KEY_ID);
+ if (resultCode == RESULT_CODE_REGISTER) {
+ int priority = resultData.getInt(RESULT_KEY_PRIORITY);
+ final IOnBackInvokedCallback callback = IOnBackInvokedCallback.Stub.asInterface(
+ resultData.getBinder(RESULT_KEY_CALLBACK));
+ registerReceivedCallback(
+ callback, priority, callbackId, receivingDispatcher);
+ } else if (resultCode == RESULT_CODE_UNREGISTER) {
+ unregisterReceivedCallback(callbackId, receivingDispatcher);
+ }
+ }
+
+ private void registerReceivedCallback(
+ @NonNull IOnBackInvokedCallback iCallback,
+ @OnBackInvokedDispatcher.Priority int priority,
+ int callbackId,
+ @NonNull OnBackInvokedDispatcher receivingDispatcher) {
+ final ImeOnBackInvokedCallback imeCallback =
+ new ImeOnBackInvokedCallback(iCallback);
+ mImeCallbackMap.put(callbackId, imeCallback);
+ receivingDispatcher.registerOnBackInvokedCallback(priority, imeCallback);
+ }
+
+ private void unregisterReceivedCallback(
+ int callbackId, OnBackInvokedDispatcher receivingDispatcher) {
+ final OnBackInvokedCallback callback = mImeCallbackMap.get(callbackId);
+ if (callback == null) {
+ Log.e(TAG, "Ime callback not found. Ignoring unregisterReceivedCallback. "
+ + "callbackId: " + callbackId);
+ return;
+ }
+ receivingDispatcher.unregisterOnBackInvokedCallback(callback);
+ }
+
+ /** Clears all registered callbacks on the instance. */
+ public void clear() {
+ mImeCallbackMap.clear();
+ }
+
+ static class ImeOnBackInvokedCallback implements OnBackInvokedCallback {
+ @NonNull
+ private final IOnBackInvokedCallback mIOnBackInvokedCallback;
+
+ ImeOnBackInvokedCallback(@NonNull IOnBackInvokedCallback iCallback) {
+ mIOnBackInvokedCallback = iCallback;
+ }
+
+ @Override
+ public void onBackInvoked() {
+ try {
+ if (mIOnBackInvokedCallback != null) {
+ mIOnBackInvokedCallback.onBackInvoked();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception when invoking forwarded callback. e: ", e);
+ }
+ }
+
+ IOnBackInvokedCallback getIOnBackInvokedCallback() {
+ return mIOnBackInvokedCallback;
+ }
+ }
+}
diff --git a/core/java/android/window/OnBackInvokedDispatcher.java b/core/java/android/window/OnBackInvokedDispatcher.java
index 6bc2b5043e79..3539049af219 100644
--- a/core/java/android/window/OnBackInvokedDispatcher.java
+++ b/core/java/android/window/OnBackInvokedDispatcher.java
@@ -96,4 +96,19 @@ public interface OnBackInvokedDispatcher {
* @hide
*/
default void registerSystemOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback) { }
+
+
+ /**
+ * Sets an {@link ImeOnBackInvokedDispatcher} to forward {@link OnBackInvokedCallback}s
+ * from IME to the app process to be registered on the app window.
+ *
+ * Only call this on the IME window. Create the {@link ImeOnBackInvokedDispatcher} from
+ * the application process and override
+ * {@link ImeOnBackInvokedDispatcher#getReceivingDispatcher()} to point to the app
+ * window's {@link WindowOnBackInvokedDispatcher}.
+ *
+ * @hide
+ */
+ default void setImeOnBackInvokedDispatcher(
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { }
}
diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
index 44093971a23e..bedf5038f669 100644
--- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
@@ -49,6 +49,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
private final List<Pair<OnBackInvokedCallback, Integer>> mCallbacks = new ArrayList<>();
private final Object mLock = new Object();
private OnBackInvokedDispatcher mActualDispatcher = null;
+ private ImeOnBackInvokedDispatcher mImeDispatcher;
@Override
public void registerOnBackInvokedCallback(
@@ -108,6 +109,9 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
Log.v(TAG, String.format("Proxy transferring %d callbacks to %s", mCallbacks.size(),
mActualDispatcher));
}
+ if (mImeDispatcher != null) {
+ mActualDispatcher.setImeOnBackInvokedDispatcher(mImeDispatcher);
+ }
for (Pair<OnBackInvokedCallback, Integer> callbackPair : mCallbacks) {
int priority = callbackPair.second;
if (priority >= 0) {
@@ -117,6 +121,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
}
}
mCallbacks.clear();
+ mImeDispatcher = null;
}
private void clearCallbacksOnDispatcher() {
@@ -142,6 +147,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
}
synchronized (mLock) {
mCallbacks.clear();
+ mImeDispatcher = null;
}
}
@@ -169,4 +175,14 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
transferCallbacksToDispatcher();
}
}
+
+ @Override
+ public void setImeOnBackInvokedDispatcher(
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
+ if (mActualDispatcher != null) {
+ mActualDispatcher.setImeOnBackInvokedDispatcher(imeDispatcher);
+ } else {
+ mImeDispatcher = imeDispatcher;
+ }
+ }
}
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 781859cecb2c..edfdbcc1f4f8 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -55,6 +55,8 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
.getInt("persist.wm.debug.predictive_back", 1) != 0;
private static final boolean ALWAYS_ENFORCE_PREDICTIVE_BACK = SystemProperties
.getInt("persist.wm.debug.predictive_back_always_enforce", 0) != 0;
+ @Nullable
+ private ImeOnBackInvokedDispatcher mImeDispatcher;
/** Convenience hashmap to quickly decide if a callback has been added. */
private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>();
@@ -94,6 +96,10 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
private void registerOnBackInvokedCallbackUnchecked(
@NonNull OnBackInvokedCallback callback, @Priority int priority) {
+ if (mImeDispatcher != null) {
+ mImeDispatcher.registerOnBackInvokedCallback(priority, callback);
+ return;
+ }
if (!mOnBackInvokedCallbacks.containsKey(priority)) {
mOnBackInvokedCallbacks.put(priority, new ArrayList<>());
}
@@ -120,6 +126,10 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
@Override
public void unregisterOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback) {
+ if (mImeDispatcher != null) {
+ mImeDispatcher.unregisterOnBackInvokedCallback(callback);
+ return;
+ }
if (!mAllCallbacks.containsKey(callback)) {
if (DEBUG) {
Log.i(TAG, "Callback not found. returning...");
@@ -153,6 +163,9 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
}
mAllCallbacks.clear();
mOnBackInvokedCallbacks.clear();
+ if (mImeDispatcher != null) {
+ mImeDispatcher = null;
+ }
}
private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallback callback) {
@@ -160,14 +173,18 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
return;
}
try {
- if (callback == null) {
- mWindowSession.setOnBackInvokedCallbackInfo(mWindow, null);
- } else {
+ OnBackInvokedCallbackInfo callbackInfo = null;
+ if (callback != null) {
int priority = mAllCallbacks.get(callback);
- mWindowSession.setOnBackInvokedCallbackInfo(
- mWindow, new OnBackInvokedCallbackInfo(
- new OnBackInvokedCallbackWrapper(callback), priority));
+ final IOnBackInvokedCallback iCallback =
+ callback instanceof ImeOnBackInvokedDispatcher
+ .ImeOnBackInvokedCallback
+ ? ((ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback)
+ callback).getIOnBackInvokedCallback()
+ : new OnBackInvokedCallbackWrapper(callback);
+ callbackInfo = new OnBackInvokedCallbackInfo(iCallback, priority);
}
+ mWindowSession.setOnBackInvokedCallbackInfo(mWindow, callbackInfo);
if (DEBUG && callback == null) {
Log.d(TAG, TextUtils.formatSimple("setTopOnBackInvokedCallback(null) Callers:%s",
Debug.getCallers(5, " ")));
@@ -190,7 +207,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
return null;
}
- private static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
+ static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
private final WeakReference<OnBackInvokedCallback> mCallback;
OnBackInvokedCallbackWrapper(@NonNull OnBackInvokedCallback callback) {
@@ -270,4 +287,10 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
return featureFlagEnabled && (appRequestsPredictiveBack || ALWAYS_ENFORCE_PREDICTIVE_BACK);
}
+
+ @Override
+ public void setImeOnBackInvokedDispatcher(
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
+ mImeDispatcher = imeDispatcher;
+ }
}
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 7db4243d3a83..0976f45c02b0 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -21,8 +21,10 @@ import static android.window.ConfigurationHelper.shouldUpdateResources;
import android.annotation.AnyThread;
import android.annotation.BinderThread;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityThread;
import android.app.IWindowToken;
import android.app.ResourcesManager;
import android.content.Context;
@@ -33,7 +35,6 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.IWindowManager;
@@ -42,6 +43,7 @@ import android.view.WindowManagerGlobal;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.lang.ref.WeakReference;
@@ -76,7 +78,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
private boolean mAttachToWindowContainer;
- private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final Handler mHandler = ActivityThread.currentActivityThread().getHandler();
/**
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
@@ -188,8 +190,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
@BinderThread
@Override
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
- mHandler.post(() -> onConfigurationChanged(newConfig, newDisplayId,
- true /* shouldReportConfigChange */));
+ mHandler.post(PooledLambda.obtainRunnable(this::onConfigurationChanged, newConfig,
+ newDisplayId, true /* shouldReportConfigChange */).recycleOnUse());
}
// TODO(b/192048581): rewrite this method based on WindowContext and WindowProviderService
@@ -279,12 +281,16 @@ public class WindowTokenClient extends IWindowToken.Stub {
@BinderThread
@Override
public void onWindowTokenRemoved() {
- mHandler.post(() -> {
- final Context context = mContextRef.get();
- if (context != null) {
- context.destroy();
- mContextRef.clear();
- }
- });
+ mHandler.post(PooledLambda.obtainRunnable(
+ WindowTokenClient::onWindowTokenRemovedInner, this).recycleOnUse());
+ }
+
+ @MainThread
+ private void onWindowTokenRemovedInner() {
+ final Context context = mContextRef.get();
+ if (context != null) {
+ context.destroy();
+ mContextRef.clear();
+ }
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 3fee914f2def..781b6d5459ca 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -971,7 +971,8 @@ public class ChooserActivity extends ResolverActivity implements
getChooserActivityLogger().logShareTargetSelected(
SELECTION_TYPE_COPY,
"",
- -1);
+ -1,
+ false);
setResult(RESULT_OK);
finish();
@@ -1155,7 +1156,8 @@ public class ChooserActivity extends ResolverActivity implements
getChooserActivityLogger().logShareTargetSelected(
SELECTION_TYPE_NEARBY,
"",
- -1);
+ -1,
+ false);
// Action bar is user-independent, always start as primary
safelyStartActivityAsUser(ti, getPersonalProfileUserHandle());
finish();
@@ -1177,7 +1179,8 @@ public class ChooserActivity extends ResolverActivity implements
getChooserActivityLogger().logShareTargetSelected(
SELECTION_TYPE_EDIT,
"",
- -1);
+ -1,
+ false);
// Action bar is user-independent, always start as primary
safelyStartActivityAsUser(ti, getPersonalProfileUserHandle());
finish();
@@ -1754,7 +1757,8 @@ public class ChooserActivity extends ResolverActivity implements
target.getComponentName().getPackageName()
+ target.getTitle().toString(),
mMaxHashSaltDays);
- directTargetAlsoRanked = getRankedPosition((SelectableTargetInfo) targetInfo);
+ SelectableTargetInfo selectableTargetInfo = (SelectableTargetInfo) targetInfo;
+ directTargetAlsoRanked = getRankedPosition(selectableTargetInfo);
if (mCallerChooserTargets != null) {
numCallerProvided = mCallerChooserTargets.length;
@@ -1762,7 +1766,8 @@ public class ChooserActivity extends ResolverActivity implements
getChooserActivityLogger().logShareTargetSelected(
SELECTION_TYPE_SERVICE,
targetInfo.getResolveInfo().activityInfo.processName,
- value
+ value,
+ selectableTargetInfo.isPinned()
);
break;
case ChooserListAdapter.TARGET_CALLER:
@@ -1773,7 +1778,8 @@ public class ChooserActivity extends ResolverActivity implements
getChooserActivityLogger().logShareTargetSelected(
SELECTION_TYPE_APP,
targetInfo.getResolveInfo().activityInfo.processName,
- value
+ value,
+ targetInfo.isPinned()
);
break;
case ChooserListAdapter.TARGET_STANDARD_AZ:
@@ -1784,7 +1790,8 @@ public class ChooserActivity extends ResolverActivity implements
getChooserActivityLogger().logShareTargetSelected(
SELECTION_TYPE_STANDARD,
targetInfo.getResolveInfo().activityInfo.processName,
- value
+ value,
+ false
);
break;
}
diff --git a/core/java/com/android/internal/app/ChooserActivityLogger.java b/core/java/com/android/internal/app/ChooserActivityLogger.java
index 321730786471..bb7d50af4200 100644
--- a/core/java/com/android/internal/app/ChooserActivityLogger.java
+++ b/core/java/com/android/internal/app/ChooserActivityLogger.java
@@ -34,7 +34,8 @@ public interface ChooserActivityLogger {
int appProvidedApp, boolean isWorkprofile, int previewType, String intent);
/** Logs a UiEventReported event for the system sharesheet when the user selects a target. */
- void logShareTargetSelected(int targetType, String packageName, int positionPicked);
+ void logShareTargetSelected(int targetType, String packageName, int positionPicked,
+ boolean isPinned);
/** Logs a UiEventReported event for the system sharesheet being triggered by the user. */
default void logSharesheetTriggered() {
diff --git a/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java b/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java
index 48bdba3f5dae..e3cc4f12fcc6 100644
--- a/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java
+++ b/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java
@@ -51,12 +51,14 @@ public class ChooserActivityLoggerImpl implements ChooserActivityLogger {
}
@Override
- public void logShareTargetSelected(int targetType, String packageName, int positionPicked) {
+ public void logShareTargetSelected(int targetType, String packageName, int positionPicked,
+ boolean isPinned) {
FrameworkStatsLog.write(FrameworkStatsLog.RANKING_SELECTED,
/* event_id = 1 */ SharesheetTargetSelectedEvent.fromTargetType(targetType).getId(),
/* package_name = 2 */ packageName,
/* instance_id = 3 */ getInstanceId().getId(),
- /* position_picked = 4 */ positionPicked);
+ /* position_picked = 4 */ positionPicked,
+ /* is_pinned = 5 */ isPinned);
}
@Override
diff --git a/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
index c5b21ac4da90..e7f80a7f6071 100644
--- a/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
@@ -589,7 +589,7 @@ class ResolverRankerServiceResolverComparator extends AbstractResolverComparator
MetricsLogger metricsLogger = new MetricsLogger();
LogMaker log = new LogMaker(MetricsEvent.ACTION_TARGET_SELECTED);
log.setComponentName(mRankerServiceName);
- log.addTaggedData(MetricsEvent.FIELD_IS_CATEGORY_USED, mAnnotationsUsed);
+ log.addTaggedData(MetricsEvent.FIELD_IS_CATEGORY_USED, mAnnotationsUsed ? 1 : 0);
log.addTaggedData(MetricsEvent.FIELD_RANKED_POSITION, selectedPos);
metricsLogger.write(log);
}
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 957a6365739d..e56d92b48528 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -91,7 +91,12 @@ public class UnlaunchableAppActivity extends Activity
} else {
builder.setPositiveButton(R.string.ok, null);
}
- builder.show();
+ final AlertDialog dialog = builder.create();
+ dialog.create();
+ // Prevents screen overlay attack.
+ getWindow().setHideOverlayWindows(true);
+ dialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
+ dialog.show();
}
private String getDialogTitle() {
diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
index 983e0fe6144e..ffbf646a345c 100644
--- a/core/java/com/android/internal/logging/UiEventLoggerImpl.java
+++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
@@ -69,7 +69,8 @@ public class UiEventLoggerImpl implements UiEventLogger {
/* event_id = 1 */ eventID,
/* package_name = 2 */ packageName,
/* instance_id = 3 */ 0,
- /* position_picked = 4 */ position);
+ /* position_picked = 4 */ position,
+ /* is_pinned = 5 */ false);
}
}
@@ -82,7 +83,8 @@ public class UiEventLoggerImpl implements UiEventLogger {
/* event_id = 1 */ eventID,
/* package_name = 2 */ packageName,
/* instance_id = 3 */ instance.getId(),
- /* position_picked = 4 */ position);
+ /* position_picked = 4 */ position,
+ /* is_pinned = 5 */ false);
} else if ((eventID > 0)) {
logWithPosition(event, uid, packageName, position);
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 1db4bbba9ad5..ea5797d752d7 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1262,7 +1262,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
}
- if (forceConsumingNavBar && !mDrawLegacyNavigationBarBackgroundHandled) {
+ if (forceConsumingNavBar && !hideNavigation && !mDrawLegacyNavigationBarBackgroundHandled) {
mBackgroundInsets = Insets.of(mLastLeftInset, 0, mLastRightInset, mLastBottomInset);
} else {
mBackgroundInsets = Insets.NONE;
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 40d89db6165c..4e2526a281b3 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -23,6 +23,7 @@ import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputMethodSubtype;
+import android.window.ImeOnBackInvokedDispatcher;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.IInputContext;
@@ -47,7 +48,8 @@ oneway interface IInputMethod {
void unbindInput();
void startInput(in IBinder startInputToken, in IInputContext inputContext,
- in EditorInfo attribute, boolean restarting, int navigationBarFlags);
+ in EditorInfo attribute, boolean restarting, int navigationBarFlags,
+ in ImeOnBackInvokedDispatcher imeDispatcher);
void onNavButtonFlagsChanged(int navButtonFlags);
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index d7bb2cb10b8c..315776045afe 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -20,6 +20,7 @@ import android.os.ResultReceiver;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import android.view.inputmethod.EditorInfo;
+import android.window.ImeOnBackInvokedDispatcher;
import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
@@ -57,7 +58,7 @@ interface IInputMethodManager {
/* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
int windowFlags, in EditorInfo attribute, in IInputContext inputContext,
in IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
- int unverifiedTargetSdkVersion);
+ int unverifiedTargetSdkVersion, in ImeOnBackInvokedDispatcher imeDispatcher);
void showInputMethodPickerFromClient(in IInputMethodClient client,
int auxiliarySubtypeMode);
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index b6fbe206a262..f24c66695052 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1264,6 +1264,12 @@ static jint convertAudioProfileFromNative(JNIEnv *env, jobject *jAudioProfile,
size_t numPositionMasks = 0;
size_t numIndexMasks = 0;
+ int audioFormat = audioFormatFromNative(nAudioProfile->format);
+ if (audioFormat == ENCODING_INVALID) {
+ ALOGW("Unknown native audio format for JAVA API: %u", nAudioProfile->format);
+ return AUDIO_JAVA_BAD_VALUE;
+ }
+
// count up how many masks are positional and indexed
for (size_t index = 0; index < nAudioProfile->num_channel_masks; index++) {
const audio_channel_mask_t mask = nAudioProfile->channel_masks[index];
@@ -1306,10 +1312,9 @@ static jint convertAudioProfileFromNative(JNIEnv *env, jobject *jAudioProfile,
ALOGW("Unknown encapsulation type for JAVA API: %u", nAudioProfile->encapsulation_type);
}
- *jAudioProfile =
- env->NewObject(gAudioProfileClass, gAudioProfileCstor,
- audioFormatFromNative(nAudioProfile->format), jSamplingRates.get(),
- jChannelMasks.get(), jChannelIndexMasks.get(), encapsulationType);
+ *jAudioProfile = env->NewObject(gAudioProfileClass, gAudioProfileCstor, audioFormat,
+ jSamplingRates.get(), jChannelMasks.get(),
+ jChannelIndexMasks.get(), encapsulationType);
if (*jAudioProfile == nullptr) {
return AUDIO_JAVA_ERROR;
@@ -1368,6 +1373,10 @@ static jint convertAudioPortFromNative(JNIEnv *env, jobject *jAudioPort,
jobject jAudioProfile = nullptr;
jStatus = convertAudioProfileFromNative(env, &jAudioProfile, &nAudioPort->audio_profiles[i],
useInMask);
+ if (jStatus == AUDIO_JAVA_BAD_VALUE) {
+ // skipping Java layer unsupported audio formats
+ continue;
+ }
if (jStatus != NO_ERROR) {
jStatus = (jint)AUDIO_JAVA_ERROR;
goto exit;
@@ -2406,8 +2415,13 @@ static jint android_media_AudioSystem_getSurroundFormats(JNIEnv *env, jobject th
goto exit;
}
for (size_t i = 0; i < numSurroundFormats; i++) {
- jobject surroundFormat = env->NewObject(gIntegerClass, gIntegerCstor,
- audioFormatFromNative(surroundFormats[i]));
+ int audioFormat = audioFormatFromNative(surroundFormats[i]);
+ if (audioFormat == ENCODING_INVALID) {
+ // skipping Java layer unsupported audio formats
+ ALOGW("Unknown surround native audio format for JAVA API: %u", surroundFormats[i]);
+ continue;
+ }
+ jobject surroundFormat = env->NewObject(gIntegerClass, gIntegerCstor, audioFormat);
jobject enabled = env->NewObject(gBooleanClass, gBooleanCstor, surroundFormatsEnabled[i]);
env->CallObjectMethod(jSurroundFormats, gMapPut, surroundFormat, enabled);
env->DeleteLocalRef(surroundFormat);
@@ -2453,8 +2467,13 @@ static jint android_media_AudioSystem_getReportedSurroundFormats(JNIEnv *env, jo
goto exit;
}
for (size_t i = 0; i < numSurroundFormats; i++) {
- jobject surroundFormat = env->NewObject(gIntegerClass, gIntegerCstor,
- audioFormatFromNative(surroundFormats[i]));
+ int audioFormat = audioFormatFromNative(surroundFormats[i]);
+ if (audioFormat == ENCODING_INVALID) {
+ // skipping Java layer unsupported audio formats
+ ALOGW("Unknown surround native audio format for JAVA API: %u", surroundFormats[i]);
+ continue;
+ }
+ jobject surroundFormat = env->NewObject(gIntegerClass, gIntegerCstor, audioFormat);
env->CallObjectMethod(jSurroundFormats, gArrayListMethods.add, surroundFormat);
env->DeleteLocalRef(surroundFormat);
}
@@ -2919,6 +2938,10 @@ static jint android_media_AudioSystem_getDirectProfilesForAttributes(JNIEnv *env
for (const auto &audioProfile : audioProfiles) {
jobject jAudioProfile;
jStatus = convertAudioProfileFromNative(env, &jAudioProfile, &audioProfile, false);
+ if (jStatus == AUDIO_JAVA_BAD_VALUE) {
+ // skipping Java layer unsupported audio formats
+ continue;
+ }
if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java
index 2ecc26179964..0dca63847269 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java
@@ -44,6 +44,7 @@ public class ChooserActivityLoggerFake implements ChooserActivityLogger {
// share completed fields
public int targetType;
public int positionPicked;
+ public boolean isPinned;
CallRecord(int atomId, UiEventLogger.UiEventEnum eventId,
String packageName, InstanceId instanceId) {
@@ -68,12 +69,13 @@ public class ChooserActivityLoggerFake implements ChooserActivityLogger {
}
CallRecord(int atomId, String packageName, InstanceId instanceId, int targetType,
- int positionPicked) {
+ int positionPicked, boolean isPinned) {
this.atomId = atomId;
this.packageName = packageName;
this.instanceId = instanceId;
this.targetType = targetType;
this.positionPicked = positionPicked;
+ this.isPinned = isPinned;
}
}
@@ -112,9 +114,11 @@ public class ChooserActivityLoggerFake implements ChooserActivityLogger {
}
@Override
- public void logShareTargetSelected(int targetType, String packageName, int positionPicked) {
+ public void logShareTargetSelected(int targetType, String packageName, int positionPicked,
+ boolean isPinned) {
mCalls.add(new CallRecord(FrameworkStatsLog.RANKING_SELECTED, packageName, getInstanceId(),
- SharesheetTargetSelectedEvent.fromTargetType(targetType).getId(), positionPicked));
+ SharesheetTargetSelectedEvent.fromTargetType(targetType).getId(), positionPicked,
+ isPinned));
}
@Override
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 0e8388b7e8f3..60da2e8cba27 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2485,12 +2485,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "323235828": {
- "message": "Delaying app transition for recents animation to finish",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/AppTransitionController.java"
- },
"327461496": {
"message": "Complete pause: %s",
"level": "VERBOSE",
@@ -2581,12 +2575,6 @@
"group": "WM_DEBUG_ANIM",
"at": "com\/android\/server\/wm\/WindowContainer.java"
},
- "397105698": {
- "message": "grantEmbeddedWindowFocus remove request for win=%s dropped since no candidate was found",
- "level": "VERBOSE",
- "group": "WM_DEBUG_FOCUS",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"397382873": {
"message": "Moving to PAUSED: %s %s",
"level": "VERBOSE",
@@ -3115,6 +3103,12 @@
"group": "WM_DEBUG_LOCKTASK",
"at": "com\/android\/server\/wm\/LockTaskController.java"
},
+ "958338552": {
+ "message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"959486822": {
"message": "setSyncGroup #%d on %s",
"level": "VERBOSE",
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java
new file mode 100644
index 000000000000..4855ad0f7293
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 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 android.security.keystore2;
+
+import android.annotation.NonNull;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.Authorization;
+import android.system.keystore2.KeyDescriptor;
+
+import java.security.PrivateKey;
+import java.security.interfaces.EdECKey;
+import java.security.spec.NamedParameterSpec;
+
+/**
+ * EdEC private key (instance of {@link PrivateKey} and {@link EdECKey}) backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreEdECPrivateKey extends AndroidKeyStorePrivateKey implements EdECKey {
+ public AndroidKeyStoreEdECPrivateKey(
+ @NonNull KeyDescriptor descriptor, long keyId,
+ @NonNull Authorization[] authorizations,
+ @NonNull String algorithm,
+ @NonNull KeyStoreSecurityLevel securityLevel) {
+ super(descriptor, keyId, authorizations, algorithm, securityLevel);
+ }
+
+ @Override
+ public NamedParameterSpec getParams() {
+ return NamedParameterSpec.ED25519;
+ }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java
new file mode 100644
index 000000000000..642e08813291
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2022 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 android.security.keystore2;
+
+import android.annotation.NonNull;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+
+import java.math.BigInteger;
+import java.security.interfaces.EdECPublicKey;
+import java.security.spec.EdECPoint;
+import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * {@link EdECPublicKey} backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreEdECPublicKey extends AndroidKeyStorePublicKey
+ implements EdECPublicKey {
+ /**
+ * DER sequence, as defined in https://datatracker.ietf.org/doc/html/rfc8410#section-4 and
+ * https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.
+ * SEQUENCE (2 elem)
+ * SEQUENCE (1 elem)
+ * OBJECT IDENTIFIER 1.3.101.112 curveEd25519 (EdDSA 25519 signature algorithm)
+ * as defined in https://datatracker.ietf.org/doc/html/rfc8410#section-3
+ * BIT STRING (256 bit) as defined in
+ * https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.2
+ */
+ private static final byte[] DER_KEY_PREFIX = new byte[] {
+ 0x30,
+ 0x2a,
+ 0x30,
+ 0x05,
+ 0x06,
+ 0x03,
+ 0x2b,
+ 0x65,
+ 0x70,
+ 0x03,
+ 0x21,
+ 0x00,
+ };
+ private static final int ED25519_KEY_SIZE_BYTES = 32;
+
+ private byte[] mEncodedKey;
+ private EdECPoint mPoint;
+
+ public AndroidKeyStoreEdECPublicKey(
+ @NonNull KeyDescriptor descriptor,
+ @NonNull KeyMetadata metadata,
+ @NonNull String algorithm,
+ @NonNull KeyStoreSecurityLevel iSecurityLevel,
+ @NonNull byte[] encodedKey) {
+ super(descriptor, metadata, encodedKey, algorithm, iSecurityLevel);
+ mEncodedKey = encodedKey;
+
+ int preambleLength = matchesPreamble(DER_KEY_PREFIX, encodedKey);
+ if (preambleLength == 0) {
+ throw new IllegalArgumentException("Key size is not correct size");
+ }
+
+ mPoint = pointFromKeyByteArray(
+ Arrays.copyOfRange(encodedKey, preambleLength, encodedKey.length));
+ }
+
+ @Override
+ AndroidKeyStorePrivateKey getPrivateKey() {
+ return new AndroidKeyStoreEdECPrivateKey(
+ getUserKeyDescriptor(),
+ getKeyIdDescriptor().nspace,
+ getAuthorizations(),
+ "EdDSA",
+ getSecurityLevel());
+ }
+
+ @Override
+ public NamedParameterSpec getParams() {
+ return NamedParameterSpec.ED25519;
+ }
+
+ @Override
+ public EdECPoint getPoint() {
+ return mPoint;
+ }
+
+ private static int matchesPreamble(byte[] preamble, byte[] encoded) {
+ if (encoded.length != (preamble.length + ED25519_KEY_SIZE_BYTES)) {
+ return 0;
+ }
+ if (Arrays.compare(preamble, Arrays.copyOf(encoded, preamble.length)) != 0) {
+ return 0;
+ }
+ return preamble.length;
+ }
+
+ private static EdECPoint pointFromKeyByteArray(byte[] coordinates) {
+ Objects.requireNonNull(coordinates);
+
+ // Oddity of the key is the most-significant bit of the last byte.
+ boolean isOdd = (0x80 & coordinates[coordinates.length - 1]) != 0;
+ // Zero out the oddity bit.
+ coordinates[coordinates.length - 1] &= (byte) 0x7f;
+ // Representation of Y is in little-endian, according to rfc8032 section-3.1.
+ reverse(coordinates);
+ // The integer representing Y starts from the first bit in the coordinates array.
+ BigInteger y = new BigInteger(1, coordinates);
+ return new EdECPoint(isOdd, y);
+ }
+
+ private static void reverse(byte[] coordinateArray) {
+ int start = 0;
+ int end = coordinateArray.length - 1;
+ while (start < end) {
+ byte tmp = coordinateArray[start];
+ coordinateArray[start] = coordinateArray[end];
+ coordinateArray[end] = tmp;
+ start++;
+ end--;
+ }
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return mEncodedKey.clone();
+ }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index d31499e8b36d..0355628b8135 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -224,7 +224,6 @@ public class AndroidKeyStoreProvider extends Provider {
String jcaKeyAlgorithm = publicKey.getAlgorithm();
- KeyStoreSecurityLevel securityLevel = iSecurityLevel;
if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) {
return new AndroidKeyStoreECPublicKey(descriptor, metadata,
iSecurityLevel, (ECPublicKey) publicKey);
@@ -232,8 +231,9 @@ public class AndroidKeyStoreProvider extends Provider {
return new AndroidKeyStoreRSAPublicKey(descriptor, metadata,
iSecurityLevel, (RSAPublicKey) publicKey);
} else if (ED25519_OID.equalsIgnoreCase(jcaKeyAlgorithm)) {
- //TODO(b/214203951) missing classes in conscrypt
- throw new ProviderException("Curve " + ED25519_OID + " not supported yet");
+ final byte[] publicKeyEncoded = publicKey.getEncoded();
+ return new AndroidKeyStoreEdECPublicKey(descriptor, metadata, ED25519_OID,
+ iSecurityLevel, publicKeyEncoded);
} else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) {
//TODO(b/214203951) missing classes in conscrypt
throw new ProviderException("Curve " + X25519_ALIAS + " not supported yet");
diff --git a/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java
new file mode 100644
index 000000000000..5bd5797859c9
--- /dev/null
+++ b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 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 android.security.keystore2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.Authorization;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.math.BigInteger;
+import java.util.Base64;
+
+@RunWith(AndroidJUnit4.class)
+public class AndroidKeyStoreEdECPublicKeyTest {
+ private static KeyDescriptor descriptor() {
+ final KeyDescriptor keyDescriptor = new KeyDescriptor();
+ keyDescriptor.alias = "key";
+ keyDescriptor.blob = null;
+ keyDescriptor.domain = Domain.APP;
+ keyDescriptor.nspace = -1;
+ return keyDescriptor;
+ }
+
+ private static KeyMetadata metadata(byte[] cert, byte[] certChain) {
+ KeyMetadata metadata = new KeyMetadata();
+ metadata.authorizations = new Authorization[0];
+ metadata.certificate = cert;
+ metadata.certificateChain = certChain;
+ metadata.key = descriptor();
+ metadata.modificationTimeMs = 0;
+ metadata.keySecurityLevel = 1;
+ return metadata;
+ }
+
+ @Mock
+ private KeyStoreSecurityLevel mKeystoreSecurityLevel;
+
+ private static class EdECTestVector {
+ public final byte[] encodedKeyBytes;
+ public final boolean isOdd;
+ public final BigInteger yValue;
+
+ EdECTestVector(String b64KeyBytes, boolean isOdd, String yValue) {
+ this.encodedKeyBytes = Base64.getDecoder().decode(b64KeyBytes);
+ this.isOdd = isOdd;
+ this.yValue = new BigInteger(yValue);
+ }
+ }
+
+ private static final EdECTestVector[] ED_EC_TEST_VECTORS = new EdECTestVector[]{
+ new EdECTestVector("MCowBQYDK2VwAyEADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSo=",
+ false,
+ "19147682157189290216699341180089409126316261024914226007941553249095116672780"
+ ),
+ new EdECTestVector("MCowBQYDK2VwAyEA/0E1IRNzGj85Ot/TPeXqifkqTkdk4voleH0hIq59D9w=",
+ true,
+ "41640152188550647350742178040529506688513911269563908889464821205156322689535"
+ ),
+ new EdECTestVector("MCowBQYDK2VwAyEAunOvGuenetl9GQSXGVo5L3RIr4OOIpFIv/Zre8qTc/8=",
+ true,
+ "57647939198144376128225770417635248407428273266444593100194116168980378907578"
+ ),
+ new EdECTestVector("MCowBQYDK2VwAyEA2hHqaZ5IolswN1Yd58Y4hzhmUMCCqc4PW5A/SFLmTX8=",
+ false,
+ "57581368614046789120409806291852629847774713088410311752049592044694364885466"
+ ),
+ };
+
+ @Test
+ public void testParsingOfValidKeys() {
+ for (EdECTestVector testVector : ED_EC_TEST_VECTORS) {
+ AndroidKeyStoreEdECPublicKey pkey = new AndroidKeyStoreEdECPublicKey(descriptor(),
+ metadata(null, null), "EdDSA", mKeystoreSecurityLevel,
+ testVector.encodedKeyBytes);
+
+ assertEquals(pkey.getPoint().isXOdd(), testVector.isOdd);
+ assertEquals(pkey.getPoint().getY(), testVector.yValue);
+ }
+ }
+
+ @Test
+ public void testFailedParsingOfKeysWithDifferentOid() {
+ final byte[] testVectorWithIncorrectOid = Base64.getDecoder().decode(
+ "MCowBQYDLGVwAyEADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSo=");
+ assertThrows("OID should be unrecognized", IllegalArgumentException.class,
+ () -> new AndroidKeyStoreEdECPublicKey(descriptor(), metadata(null, null), "EdDSA",
+ mKeystoreSecurityLevel, testVectorWithIncorrectOid));
+ }
+
+ @Test
+ public void testFailedParsingOfKeysWithWrongSize() {
+ final byte[] testVectorWithIncorrectKeySize = Base64.getDecoder().decode(
+ "MCwwBQYDK2VwAyMADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSrOzg==");
+ assertThrows("Key length should be invalid", IllegalArgumentException.class,
+ () -> new AndroidKeyStoreEdECPublicKey(descriptor(), metadata(null, null), "EdDSA",
+ mKeystoreSecurityLevel, testVectorWithIncorrectKeySize));
+ }
+}
+
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 64017e176fc3..d04c34916256 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -40,6 +40,8 @@ public enum ShellProtoLogGroup implements IProtoLogGroup {
Consts.TAG_WM_SHELL),
WM_SHELL_PICTURE_IN_PICTURE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG,
false, Consts.TAG_WM_SHELL),
+ WM_SHELL_SPLIT_SCREEN(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM_SHELL),
TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");
private final boolean mEnabled;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 91f9d2522397..d543aa742377 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -54,6 +54,9 @@ import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_P
import static com.android.wm.shell.transition.Transitions.isClosingType;
import static com.android.wm.shell.transition.Transitions.isOpeningType;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -68,6 +71,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
+import android.os.Debug;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -147,7 +151,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private final int mDisplayId;
private SplitLayout mSplitLayout;
+ private ValueAnimator mDividerFadeInAnimator;
private boolean mDividerVisible;
+ private boolean mKeyguardShowing;
private final SyncTransactionQueue mSyncQueue;
private final ShellTaskOrganizer mTaskOrganizer;
private final Context mContext;
@@ -404,6 +410,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.init();
// Set false to avoid record new bounds with old task still on top;
mShouldUpdateRecents = false;
+ mIsDividerRemoteAnimating = true;
final WindowContainerTransaction wct = new WindowContainerTransaction();
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
@@ -417,7 +424,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
final IRemoteAnimationFinishedCallback finishedCallback) {
- mIsDividerRemoteAnimating = true;
RemoteAnimationTarget[] augmentedNonApps =
new RemoteAnimationTarget[nonApps.length + 1];
for (int i = 0; i < nonApps.length; ++i) {
@@ -494,8 +500,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
// Using legacy transitions, so we can't use blast sync since it conflicts.
mTaskOrganizer.applyTransaction(wct);
- mSyncQueue.runInSync(t ->
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
+ mSyncQueue.runInSync(t -> {
+ setDividerVisibility(true, t);
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+ });
}
private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) {
@@ -510,10 +518,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
} else {
mSyncQueue.queue(evictWct);
- mSyncQueue.runInSync(t -> {
- setDividerVisibility(true, t);
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
- });
}
}
@@ -623,16 +627,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
void onKeyguardVisibilityChanged(boolean showing) {
+ mKeyguardShowing = showing;
if (!mMainStage.isActive()) {
return;
}
- if (ENABLE_SHELL_TRANSITIONS) {
- // Update divider visibility so it won't float on top of keyguard.
- setDividerVisibility(!showing, null /* transaction */);
- }
-
- if (!showing && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
+ if (!mKeyguardShowing && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
if (ENABLE_SHELL_TRANSITIONS) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
@@ -643,7 +643,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
EXIT_REASON_DEVICE_FOLDED);
}
+ return;
}
+
+ setDividerVisibility(!mKeyguardShowing, null);
}
void onFinishedWakingUp() {
@@ -727,6 +730,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setResizingSplits(false /* resizing */);
t.setWindowCrop(mMainStage.mRootLeash, null)
.setWindowCrop(mSideStage.mRootLeash, null);
+ setDividerVisibility(false, t);
});
// Hide divider and reset its position.
@@ -1055,8 +1059,31 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
private void setDividerVisibility(boolean visible, @Nullable SurfaceControl.Transaction t) {
+ if (visible == mDividerVisible) {
+ return;
+ }
+
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Request to %s divider bar from %s.", TAG,
+ (visible ? "show" : "hide"), Debug.getCaller());
+
+ // Defer showing divider bar after keyguard dismissed, so it won't interfere with keyguard
+ // dismissing animation.
+ if (visible && mKeyguardShowing) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Defer showing divider bar due to keyguard showing.", TAG);
+ return;
+ }
+
mDividerVisible = visible;
sendSplitVisibilityChanged();
+
+ if (mIsDividerRemoteAnimating) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Skip animating divider bar due to it's remote animating.", TAG);
+ return;
+ }
+
if (t != null) {
applyDividerVisibility(t);
} else {
@@ -1066,15 +1093,56 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private void applyDividerVisibility(SurfaceControl.Transaction t) {
final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
- if (mIsDividerRemoteAnimating || dividerLeash == null) return;
+ if (dividerLeash == null) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Skip animating divider bar due to divider leash not ready.", TAG);
+ return;
+ }
+ if (mIsDividerRemoteAnimating) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Skip animating divider bar due to it's remote animating.", TAG);
+ return;
+ }
+
+ if (mDividerFadeInAnimator != null && mDividerFadeInAnimator.isRunning()) {
+ mDividerFadeInAnimator.cancel();
+ }
if (mDividerVisible) {
- t.show(dividerLeash);
- t.setAlpha(dividerLeash, 1);
- t.setLayer(dividerLeash, Integer.MAX_VALUE);
- t.setPosition(dividerLeash,
- mSplitLayout.getRefDividerBounds().left,
- mSplitLayout.getRefDividerBounds().top);
+ final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
+ mDividerFadeInAnimator = ValueAnimator.ofFloat(0f, 1f);
+ mDividerFadeInAnimator.addUpdateListener(animation -> {
+ if (dividerLeash == null) {
+ mDividerFadeInAnimator.cancel();
+ return;
+ }
+ transaction.setAlpha(dividerLeash, (float) animation.getAnimatedValue());
+ transaction.apply();
+ });
+ mDividerFadeInAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (dividerLeash == null) {
+ mDividerFadeInAnimator.cancel();
+ return;
+ }
+ transaction.show(dividerLeash);
+ transaction.setAlpha(dividerLeash, 0);
+ transaction.setLayer(dividerLeash, Integer.MAX_VALUE);
+ transaction.setPosition(dividerLeash,
+ mSplitLayout.getRefDividerBounds().left,
+ mSplitLayout.getRefDividerBounds().top);
+ transaction.apply();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTransactionPool.release(transaction);
+ mDividerFadeInAnimator = null;
+ }
+ });
+
+ mDividerFadeInAnimator.start();
} else {
t.hide(dividerLeash);
}
@@ -1096,10 +1164,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.init();
prepareEnterSplitScreen(wct);
mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t -> {
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
- setDividerVisibility(true, t);
- });
+ mSyncQueue.runInSync(t ->
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
}
if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
mShouldUpdateRecents = true;
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
index cf4ea467a29b..41cd31aabf05 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
@@ -37,7 +37,7 @@ class AppPairsHelper(
val displayBounds = WindowUtils.displayBounds
val secondaryAppBounds = Region.from(0,
dividerBounds.bounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right, displayBounds.bottom - WindowUtils.navigationBarHeight)
+ displayBounds.right, displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
return secondaryAppBounds
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index a510d699387e..e2da1a4565c0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -171,7 +171,7 @@ class ResizeLegacySplitScreen(
val bottomAppBounds = Region.from(0,
dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarHeight)
+ displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent())
.coversExactly(topAppBounds)
visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent())
@@ -192,7 +192,7 @@ class ResizeLegacySplitScreen(
val bottomAppBounds = Region.from(0,
dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarHeight)
+ displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent())
.coversExactly(topAppBounds)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index a55f737f2f25..ffaab652aa99 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -139,6 +139,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testLaunchToSide() {
ActivityManager.RunningTaskInfo newTask = new TestRunningTaskInfoBuilder()
.setParentTaskId(mSideStage.mRootTaskInfo.taskId).build();
@@ -173,6 +174,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testLaunchPair() {
TransitionInfo info = createEnterPairInfo();
@@ -195,6 +197,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testMonitorInSplit() {
enterSplit();
@@ -251,6 +254,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testEnterRecents() {
enterSplit();
@@ -288,6 +292,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testDismissFromBeingOccluded() {
enterSplit();
@@ -325,6 +330,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testDismissFromMultiWindowSupport() {
enterSplit();
@@ -346,6 +352,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testDismissSnap() {
enterSplit();
@@ -370,6 +377,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testDismissFromAppFinish() {
enterSplit();
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 37cbf3017f0b..5e918641e49f 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -484,6 +484,14 @@ public class CompanionDeviceActivity extends FragmentActivity implements
if (deviceFilterPairs.isEmpty()) return;
mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
+ // No need to show user consent dialog if it is a singleDevice
+ // and isSkipPrompt(true) AssociationRequest.
+ // See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
+ if (mRequest.isSkipPrompt()) {
+ mSingleDeviceSpinner.setVisibility(View.GONE);
+ onUserSelectedDevice(mSelectedDevice);
+ return;
+ }
final String deviceName = mSelectedDevice.getDisplayName();
final Spanned title = getHtmlFromResources(
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_content_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_content_layout.xml
index 25f0771b2170..72b569f22d6c 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_content_layout.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_content_layout.xml
@@ -25,7 +25,7 @@
android:fitsSystemWindows="true"
android:outlineAmbientShadowColor="@android:color/transparent"
android:outlineSpotShadowColor="@android:color/transparent"
- android:background="?android:attr/colorPrimary"
+ android:background="@android:color/transparent"
android:theme="@style/Theme.CollapsingToolbar.Settings">
<com.google.android.material.appbar.CollapsingToolbarLayout
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java
index 72383fe59e7e..dbb4b5017e6b 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java
@@ -20,6 +20,7 @@ import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
@@ -29,6 +30,7 @@ import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
@@ -41,6 +43,7 @@ import com.google.android.material.appbar.CollapsingToolbarLayout;
* This widget is wrapping the collapsing toolbar and can be directly used by the
* {@link AppCompatActivity}.
*/
+@RequiresApi(Build.VERSION_CODES.S)
public class CollapsingCoordinatorLayout extends CoordinatorLayout {
private static final String TAG = "CollapsingCoordinatorLayout";
private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index ac306361386e..6766cdd0beb6 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -40,6 +40,8 @@ public class FooterPreference extends Preference {
static final int ORDER_FOOTER = Integer.MAX_VALUE - 1;
@VisibleForTesting
View.OnClickListener mLearnMoreListener;
+ @VisibleForTesting
+ int mIconVisibility = View.VISIBLE;
private CharSequence mContentDescription;
private CharSequence mLearnMoreText;
private CharSequence mLearnMoreContentDescription;
@@ -84,6 +86,9 @@ public class FooterPreference extends Preference {
} else {
learnMore.setVisibility(View.GONE);
}
+
+ View icon = holder.itemView.findViewById(R.id.icon_frame);
+ icon.setVisibility(mIconVisibility);
}
@Override
@@ -165,6 +170,17 @@ public class FooterPreference extends Preference {
}
}
+ /**
+ * Set visibility of footer icon.
+ */
+ public void setIconVisibility(int iconVisibility) {
+ if (mIconVisibility == iconVisibility) {
+ return;
+ }
+ mIconVisibility = iconVisibility;
+ notifyChanged();
+ }
+
private void init() {
setLayoutResource(R.layout.preference_footer);
if (getIcon() == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 284da73efb6f..2f30baa79b9d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -234,5 +234,10 @@ public class RestrictedPreferenceHelper {
if (!(mPreference instanceof RestrictedTopLevelPreference)) {
mPreference.setEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
}
+
+ if (mPreference instanceof PrimarySwitchPreference) {
+ ((PrimarySwitchPreference) mPreference)
+ .setSwitchEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index fdb06072bbd1..6b9daa35f9ca 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -863,6 +863,30 @@ public class ApplicationsState {
}
}
+ /**
+ * Activate session to enable a class that implements Callbacks to receive the callback.
+ */
+ public void activateSession() {
+ synchronized (mEntriesMap) {
+ if (!mResumed) {
+ mResumed = true;
+ mSessionsChanged = true;
+ }
+ }
+ }
+
+ /**
+ * Deactivate session to disable a class that implements Callbacks to get the callback.
+ */
+ public void deactivateSession() {
+ synchronized (mEntriesMap) {
+ if (mResumed) {
+ mResumed = false;
+ mSessionsChanged = true;
+ }
+ }
+ }
+
public ArrayList<AppEntry> getAllApps() {
synchronized (mEntriesMap) {
return new ArrayList<>(mAppEntries);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 4ee21229e364..6919cf237853 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -1376,7 +1376,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
/**
* Store the member devices that are in the same coordinated set.
*/
- public void setMemberDevice(CachedBluetoothDevice memberDevice) {
+ public void addMemberDevice(CachedBluetoothDevice memberDevice) {
mMemberDevices.add(memberDevice);
}
@@ -1393,24 +1393,24 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
* device and member devices.
*
* @param prevMainDevice the previous Main device, it will be added into the member device set.
- * @param newMainDevie the new Main device, it will be removed from the member device set.
+ * @param newMainDevice the new Main device, it will be removed from the member device set.
*/
public void switchMemberDeviceContent(CachedBluetoothDevice prevMainDevice,
- CachedBluetoothDevice newMainDevie) {
+ CachedBluetoothDevice newMainDevice) {
// Backup from main device
final BluetoothDevice tmpDevice = mDevice;
final short tmpRssi = mRssi;
final boolean tmpJustDiscovered = mJustDiscovered;
// Set main device from sub device
- mDevice = newMainDevie.mDevice;
- mRssi = newMainDevie.mRssi;
- mJustDiscovered = newMainDevie.mJustDiscovered;
- setMemberDevice(prevMainDevice);
- mMemberDevices.remove(newMainDevie);
+ mDevice = newMainDevice.mDevice;
+ mRssi = newMainDevice.mRssi;
+ mJustDiscovered = newMainDevice.mJustDiscovered;
+ addMemberDevice(prevMainDevice);
+ mMemberDevices.remove(newMainDevice);
// Set sub device from backup
- newMainDevie.mDevice = tmpDevice;
- newMainDevie.mRssi = tmpRssi;
- newMainDevie.mJustDiscovered = tmpJustDiscovered;
+ newMainDevice.mDevice = tmpDevice;
+ newMainDevice.mRssi = tmpRssi;
+ newMainDevice.mJustDiscovered = tmpJustDiscovered;
fetchActiveDevices();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index cc56a212aea1..89e10c4b5e11 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -85,7 +85,7 @@ public class CsipDeviceManager {
// Once there is other devices with the same groupId, to add new device as member
// devices.
if (CsipDevice != null) {
- CsipDevice.setMemberDevice(newDevice);
+ CsipDevice.addMemberDevice(newDevice);
newDevice.setName(CsipDevice.getName());
return true;
}
@@ -148,7 +148,7 @@ public class CsipDeviceManager {
log("onGroupIdChanged: removed from UI device =" + cachedDevice
+ ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex);
- mainDevice.setMemberDevice(cachedDevice);
+ mainDevice.addMemberDevice(cachedDevice);
mCachedDevices.remove(i);
mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
break;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 298ee90d311d..bef1d9cbcde1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -40,7 +40,6 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Map;
@RunWith(RobolectricTestRunner.class)
@@ -503,8 +502,8 @@ public class CachedBluetoothDeviceManagerTest {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3);
- cachedDevice1.setMemberDevice(cachedDevice2);
- cachedDevice1.setMemberDevice(cachedDevice3);
+ cachedDevice1.addMemberDevice(cachedDevice2);
+ cachedDevice1.addMemberDevice(cachedDevice3);
assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice2);
assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice3);
@@ -524,7 +523,7 @@ public class CachedBluetoothDeviceManagerTest {
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
cachedDevice1.setGroupId(1);
cachedDevice2.setGroupId(1);
- cachedDevice1.setMemberDevice(cachedDevice2);
+ cachedDevice1.addMemberDevice(cachedDevice2);
// Call onDeviceUnpaired for the one in mCachedDevices.
mCachedDeviceManager.onDeviceUnpaired(cachedDevice1);
@@ -541,7 +540,7 @@ public class CachedBluetoothDeviceManagerTest {
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
cachedDevice1.setGroupId(1);
cachedDevice2.setGroupId(1);
- cachedDevice1.setMemberDevice(cachedDevice2);
+ cachedDevice1.addMemberDevice(cachedDevice2);
// Call onDeviceUnpaired for the one in mCachedDevices.
mCachedDeviceManager.onDeviceUnpaired(cachedDevice2);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
index 61a28aab061f..9abb27e68398 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.view.LayoutInflater;
+import android.view.View;
import android.widget.TextView;
import androidx.preference.PreferenceViewHolder;
@@ -61,7 +62,7 @@ public class FooterPreferenceTest {
mFooterPreference.onBindViewHolder(holder);
assertThat(((TextView) holder.findViewById(
- R.id.settingslib_learn_more)).getText().toString())
+ R.id.settingslib_learn_more)).getText().toString())
.isEqualTo("Custom learn more");
}
@@ -86,4 +87,11 @@ public class FooterPreferenceTest {
assertThat(mFooterPreference.mLearnMoreListener).isNotNull();
}
+
+ @Test
+ public void setIconVisibility_shouldReturnSameVisibilityType() {
+ mFooterPreference.setIconVisibility(View.GONE);
+
+ assertThat(mFooterPreference.mIconVisibility).isEqualTo(View.GONE);
+ }
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 3029781f3e99..5eaf553a2047 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -120,6 +120,9 @@ public class SecureSettings {
Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
+ Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS,
+ Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
Settings.Secure.VR_DISPLAY_MODE,
Settings.Secure.NOTIFICATION_BADGING,
Settings.Secure.NOTIFICATION_DISMISS_RTL,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index a4da49713f87..9ee7b654046f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -18,6 +18,7 @@ package android.provider.settings.validators;
import static android.provider.settings.validators.SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_COMPONENT_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_PACKAGE_LIST_VALIDATOR;
@@ -176,6 +177,10 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_WAKE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ ANY_STRING_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_WAKE_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SystemUI/res/layout/alert_dialog_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_systemui.xml
index 528f603c6a83..fd0623812745 100644
--- a/packages/SystemUI/res/layout/alert_dialog_systemui.xml
+++ b/packages/SystemUI/res/layout/alert_dialog_systemui.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
- ~ Copyright (C) 2021 The Android Open Source Project
+ ~ Copyright (C) 2022 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.
@@ -15,88 +14,83 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<androidx.core.widget.NestedScrollView
+
+<com.android.internal.widget.AlertDialogLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@*android:id/parentPanel"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal|top"
+ android:orientation="vertical"
+ android:paddingTop="@dimen/dialog_top_padding"
+>
+
+ <include layout="@layout/alert_dialog_title_systemui" />
- <com.android.internal.widget.AlertDialogLayout
- android:id="@*android:id/parentPanel"
+ <FrameLayout
+ android:id="@*android:id/contentPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="center_horizontal|top"
- android:orientation="vertical"
- android:paddingTop="@dimen/dialog_top_padding"
- >
+ android:minHeight="48dp"
+ android:paddingStart="@dimen/dialog_side_padding"
+ android:paddingEnd="@dimen/dialog_side_padding"
+ >
- <include layout="@layout/alert_dialog_title_systemui" />
-
- <FrameLayout
- android:id="@*android:id/contentPanel"
+ <ScrollView
+ android:id="@*android:id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:paddingStart="@dimen/dialog_side_padding"
- android:paddingEnd="@dimen/dialog_side_padding"
- >
+ android:clipToPadding="false">
- <ScrollView
- android:id="@*android:id/scrollView"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:clipToPadding="false">
+ android:orientation="vertical">
- <LinearLayout
+ <Space
+ android:id="@*android:id/textSpacerNoTitle"
+ android:visibility="gone"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:layout_height="0dp" />
- <Space
- android:id="@*android:id/textSpacerNoTitle"
- android:visibility="gone"
- android:layout_width="match_parent"
- android:layout_height="0dp" />
+ <TextView
+ android:id="@*android:id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.Dialog.Body.Message" />
- <TextView
- android:id="@*android:id/message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.Dialog.Body.Message" />
+ <Space
+ android:id="@*android:id/textSpacerNoButtons"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="6dp" />
+ </LinearLayout>
+ </ScrollView>
+ </FrameLayout>
- <Space
- android:id="@*android:id/textSpacerNoButtons"
- android:visibility="gone"
- android:layout_width="match_parent"
- android:layout_height="6dp" />
- </LinearLayout>
- </ScrollView>
- </FrameLayout>
+ <FrameLayout
+ android:id="@*android:id/customPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:paddingStart="@dimen/dialog_side_padding"
+ android:paddingEnd="@dimen/dialog_side_padding"
+ >
<FrameLayout
- android:id="@*android:id/customPanel"
+ android:id="@*android:id/custom"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:paddingStart="@dimen/dialog_side_padding"
- android:paddingEnd="@dimen/dialog_side_padding"
- >
+ android:layout_height="wrap_content" />
+ </FrameLayout>
- <FrameLayout
- android:id="@*android:id/custom"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- </FrameLayout>
-
- <FrameLayout
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/dialog_side_padding"
+ android:paddingEnd="@dimen/dialog_side_padding">
+ <include
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="@dimen/dialog_side_padding"
- android:paddingEnd="@dimen/dialog_side_padding">
- <include
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- layout="@layout/alert_dialog_button_bar_systemui" />
- </FrameLayout>
- </com.android.internal.widget.AlertDialogLayout>
-
-</androidx.core.widget.NestedScrollView> \ No newline at end of file
+ layout="@layout/alert_dialog_button_bar_systemui" />
+ </FrameLayout>
+</com.android.internal.widget.AlertDialogLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/scrollable_alert_dialog_systemui.xml b/packages/SystemUI/res/layout/scrollable_alert_dialog_systemui.xml
new file mode 100644
index 000000000000..71bb938dfdf4
--- /dev/null
+++ b/packages/SystemUI/res/layout/scrollable_alert_dialog_systemui.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ 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.
+ -->
+<androidx.core.widget.NestedScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <include layout="@layout/alert_dialog_systemui" />
+
+</androidx.core.widget.NestedScrollView> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index f9e73ec3a76f..0c25f5473416 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -380,7 +380,7 @@
<item name="android:buttonBarNegativeButtonStyle">@style/Widget.Dialog.Button.BorderButton</item>
<item name="android:buttonBarNeutralButtonStyle">@style/Widget.Dialog.Button.BorderButton</item>
<item name="android:colorBackground">?androidprv:attr/colorSurface</item>
- <item name="android:alertDialogStyle">@style/AlertDialogStyle</item>
+ <item name="android:alertDialogStyle">@style/ScrollableAlertDialogStyle</item>
<item name="android:buttonBarStyle">@style/ButtonBarStyle</item>
<item name="android:buttonBarButtonStyle">@style/Widget.Dialog.Button.Large</item>
</style>
@@ -389,6 +389,10 @@
<item name="android:layout">@layout/alert_dialog_systemui</item>
</style>
+ <style name="ScrollableAlertDialogStyle" parent="@androidprv:style/AlertDialog.DeviceDefault">
+ <item name="android:layout">@layout/scrollable_alert_dialog_systemui</item>
+ </style>
+
<style name="ButtonBarStyle" parent="@androidprv:style/DeviceDefault.ButtonBar.AlertDialog">
<item name="android:paddingTop">@dimen/dialog_button_bar_top_padding</item>
<item name="android:paddingBottom">@dimen/dialog_bottom_padding</item>
@@ -994,6 +998,7 @@
<style name="Theme.SystemUI.Dialog.Cast">
<item name="android:textAppearanceMedium">@style/TextAppearance.CastItem</item>
+ <item name="android:alertDialogStyle">@style/AlertDialogStyle</item>
</style>
<!-- ************************************************************************************* -->
diff --git a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
index f195d2094d6a..38fa35453418 100644
--- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
@@ -16,14 +16,20 @@
package com.android.keyguard
+import android.annotation.IntDef
import android.content.ContentResolver
import android.database.ContentObserver
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT
import android.net.Uri
import android.os.Handler
import android.os.UserHandle
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE
+import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
@@ -44,6 +50,20 @@ class ActiveUnlockConfig @Inject constructor(
dumpManager: DumpManager
) : Dumpable {
+ companion object {
+ const val TAG = "ActiveUnlockConfig"
+
+ const val BIOMETRIC_TYPE_NONE = 0
+ const val BIOMETRIC_TYPE_ANY_FACE = 1
+ const val BIOMETRIC_TYPE_ANY_FINGERPRINT = 2
+ const val BIOMETRIC_TYPE_UNDER_DISPLAY_FINGERPRINT = 3
+ }
+
+ @Retention(AnnotationRetention.SOURCE)
+ @IntDef(BIOMETRIC_TYPE_NONE, BIOMETRIC_TYPE_ANY_FACE, BIOMETRIC_TYPE_ANY_FINGERPRINT,
+ BIOMETRIC_TYPE_UNDER_DISPLAY_FINGERPRINT)
+ annotation class BiometricType
+
/**
* Indicates the origin for an active unlock request.
*/
@@ -51,35 +71,50 @@ class ActiveUnlockConfig @Inject constructor(
WAKE, UNLOCK_INTENT, BIOMETRIC_FAIL, ASSISTANT
}
+ var keyguardUpdateMonitor: KeyguardUpdateMonitor? = null
private var requestActiveUnlockOnWakeup = false
private var requestActiveUnlockOnUnlockIntent = false
private var requestActiveUnlockOnBioFail = false
+ private var faceErrorsToTriggerBiometricFailOn = mutableSetOf(FACE_ERROR_TIMEOUT)
+ private var faceAcquireInfoToTriggerBiometricFailOn = mutableSetOf<Int>()
+ private var onUnlockIntentWhenBiometricEnrolled = mutableSetOf<Int>(BIOMETRIC_TYPE_NONE)
+
private val settingsObserver = object : ContentObserver(handler) {
- private val wakeUri: Uri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE)
- private val unlockIntentUri: Uri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT)
- private val bioFailUri: Uri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)
+ private val wakeUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE)
+ private val unlockIntentUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT)
+ private val bioFailUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)
+ private val faceErrorsUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ERRORS)
+ private val faceAcquireInfoUri =
+ secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO)
+ private val unlockIntentWhenBiometricEnrolledUri =
+ secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED)
fun register() {
- contentResolver.registerContentObserver(
- wakeUri,
- false,
- this,
- UserHandle.USER_ALL)
- contentResolver.registerContentObserver(
- unlockIntentUri,
- false,
- this,
- UserHandle.USER_ALL)
- contentResolver.registerContentObserver(
- bioFailUri,
- false,
- this,
- UserHandle.USER_ALL)
+ registerUri(
+ listOf(
+ wakeUri,
+ unlockIntentUri,
+ bioFailUri,
+ faceErrorsUri,
+ faceAcquireInfoUri,
+ unlockIntentWhenBiometricEnrolledUri
+ )
+ )
onChange(true, ArrayList(), 0, getCurrentUser())
}
+ private fun registerUri(uris: Collection<Uri>) {
+ for (uri in uris) {
+ contentResolver.registerContentObserver(
+ uri,
+ false,
+ this,
+ UserHandle.USER_ALL)
+ }
+ }
+
override fun onChange(
selfChange: Boolean,
uris: Collection<Uri>,
@@ -104,6 +139,55 @@ class ActiveUnlockConfig @Inject constructor(
requestActiveUnlockOnBioFail = secureSettings.getIntForUser(
ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 0, getCurrentUser()) == 1
}
+
+ if (selfChange || uris.contains(faceErrorsUri)) {
+ processStringArray(
+ secureSettings.getStringForUser(ACTIVE_UNLOCK_ON_FACE_ERRORS,
+ getCurrentUser()),
+ faceErrorsToTriggerBiometricFailOn,
+ setOf(FACE_ERROR_TIMEOUT))
+ }
+
+ if (selfChange || uris.contains(faceAcquireInfoUri)) {
+ processStringArray(
+ secureSettings.getStringForUser(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
+ getCurrentUser()),
+ faceAcquireInfoToTriggerBiometricFailOn,
+ setOf<Int>())
+ }
+
+ if (selfChange || uris.contains(unlockIntentWhenBiometricEnrolledUri)) {
+ processStringArray(
+ secureSettings.getStringForUser(
+ ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ getCurrentUser()),
+ onUnlockIntentWhenBiometricEnrolled,
+ setOf(BIOMETRIC_TYPE_NONE))
+ }
+ }
+
+ /**
+ * Convert a pipe-separated set of integers into a set of ints.
+ * @param stringSetting expected input are integers delineated by a pipe. For example,
+ * it may look something like this: "1|5|3".
+ * @param out updates the "out" Set will the integers between the pipes.
+ * @param default If stringSetting is null, "out" will be populated with values in "default"
+ */
+ private fun processStringArray(
+ stringSetting: String?,
+ out: MutableSet<Int>,
+ default: Set<Int>
+ ) {
+ out.clear()
+ stringSetting?.let {
+ for (code: String in stringSetting.split("|")) {
+ try {
+ out.add(code.toInt())
+ } catch (e: NumberFormatException) {
+ Log.e(TAG, "Passed an invalid setting=$code")
+ }
+ }
+ } ?: out.addAll(default)
}
}
@@ -113,6 +197,30 @@ class ActiveUnlockConfig @Inject constructor(
}
/**
+ * If any active unlock triggers are enabled.
+ */
+ fun isActiveUnlockEnabled(): Boolean {
+ return requestActiveUnlockOnWakeup || requestActiveUnlockOnUnlockIntent ||
+ requestActiveUnlockOnBioFail
+ }
+
+ /**
+ * Whether the face error code from {@link BiometricFaceConstants} should trigger
+ * active unlock on biometric failure.
+ */
+ fun shouldRequestActiveUnlockOnFaceError(errorCode: Int): Boolean {
+ return faceErrorsToTriggerBiometricFailOn.contains(errorCode)
+ }
+
+ /**
+ * Whether the face acquireInfo from {@link BiometricFaceConstants} should trigger
+ * active unlock on biometric failure.
+ */
+ fun shouldRequestActiveUnlockOnFaceAcquireInfo(acquiredInfo: Int): Boolean {
+ return faceAcquireInfoToTriggerBiometricFailOn.contains(acquiredInfo)
+ }
+
+ /**
* Whether to trigger active unlock based on where the request is coming from and
* the current settings.
*/
@@ -121,7 +229,8 @@ class ActiveUnlockConfig @Inject constructor(
ACTIVE_UNLOCK_REQUEST_ORIGIN.WAKE -> requestActiveUnlockOnWakeup
ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT ->
- requestActiveUnlockOnUnlockIntent || requestActiveUnlockOnWakeup
+ requestActiveUnlockOnUnlockIntent || requestActiveUnlockOnWakeup ||
+ (shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment())
ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL ->
requestActiveUnlockOnBioFail || requestActiveUnlockOnUnlockIntent ||
@@ -131,17 +240,55 @@ class ActiveUnlockConfig @Inject constructor(
}
}
- /**
- * If any active unlock triggers are enabled.
- */
- fun isActiveUnlockEnabled(): Boolean {
- return requestActiveUnlockOnWakeup || requestActiveUnlockOnUnlockIntent ||
- requestActiveUnlockOnBioFail
+ private fun shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment(): Boolean {
+ if (!requestActiveUnlockOnBioFail) {
+ return false
+ }
+
+ keyguardUpdateMonitor?.let {
+ val anyFaceEnrolled = it.isFaceEnrolled
+ val anyFingerprintEnrolled =
+ it.getCachedIsUnlockWithFingerprintPossible(getCurrentUser())
+ val udfpsEnrolled = it.isUdfpsEnrolled
+
+ if (!anyFaceEnrolled && !anyFingerprintEnrolled) {
+ return onUnlockIntentWhenBiometricEnrolled.contains(BIOMETRIC_TYPE_NONE)
+ }
+
+ if (!anyFaceEnrolled && anyFingerprintEnrolled) {
+ return onUnlockIntentWhenBiometricEnrolled.contains(
+ BIOMETRIC_TYPE_ANY_FINGERPRINT) ||
+ (udfpsEnrolled && onUnlockIntentWhenBiometricEnrolled.contains(
+ BIOMETRIC_TYPE_UNDER_DISPLAY_FINGERPRINT))
+ }
+
+ if (!anyFingerprintEnrolled && anyFaceEnrolled) {
+ return onUnlockIntentWhenBiometricEnrolled.contains(BIOMETRIC_TYPE_ANY_FACE)
+ }
+ }
+
+ return false
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.println("Settings:")
pw.println(" requestActiveUnlockOnWakeup=$requestActiveUnlockOnWakeup")
pw.println(" requestActiveUnlockOnUnlockIntent=$requestActiveUnlockOnUnlockIntent")
pw.println(" requestActiveUnlockOnBioFail=$requestActiveUnlockOnBioFail")
+ pw.println(" requestActiveUnlockOnUnlockIntentWhenBiometricEnrolled=" +
+ "$onUnlockIntentWhenBiometricEnrolled")
+ pw.println(" requestActiveUnlockOnFaceError=$faceErrorsToTriggerBiometricFailOn")
+ pw.println(" requestActiveUnlockOnFaceAcquireInfo=" +
+ "$faceAcquireInfoToTriggerBiometricFailOn")
+
+ pw.println("Current state:")
+ keyguardUpdateMonitor?.let {
+ pw.println(" shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment=" +
+ "${shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment()}")
+ pw.println(" faceEnrolled=${it.isFaceEnrolled}")
+ pw.println(" fpEnrolled=${
+ it.getCachedIsUnlockWithFingerprintPossible(getCurrentUser())}")
+ pw.println(" udfpsEnrolled=${it.isUdfpsEnrolled}")
+ } ?: pw.println(" keyguardUpdateMonitor is uninitialized")
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index bbe9a362b1fa..121ac299ec5b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -56,7 +56,6 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
-import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
@@ -1615,7 +1614,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
}
- if (errMsgId == BiometricFaceConstants.FACE_ERROR_TIMEOUT) {
+ if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceError(errMsgId)) {
requestActiveUnlock(
ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL,
"faceError-" + errMsgId);
@@ -1625,6 +1624,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@Override
public void onAuthenticationAcquired(int acquireInfo) {
handleFaceAcquired(acquireInfo);
+
+ if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
+ acquireInfo)) {
+ requestActiveUnlock(
+ ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL,
+ "faceAcquireInfo-" + acquireInfo);
+ }
}
};
@@ -1639,6 +1645,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean mFingerprintLockedOut;
private boolean mFingerprintLockedOutPermanent;
private boolean mFaceLockedOutPermanent;
+ private HashMap<Integer, Boolean> mIsUnlockWithFingerprintPossible = new HashMap<>();
private TelephonyManager mTelephonyManager;
/**
@@ -1889,6 +1896,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
dumpManager.registerDumpable(getClass().getName(), this);
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
mActiveUnlockConfig = activeUnlockConfiguration;
+ mActiveUnlockConfig.setKeyguardUpdateMonitor(this);
mHandler = new Handler(mainLooper) {
@Override
@@ -2329,7 +2337,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
if (shouldTriggerActiveUnlock()) {
- if (DEBUG) {
+ if (DEBUG_ACTIVE_UNLOCK) {
Log.d("ActiveUnlock", "initiate active unlock triggerReason=" + reason);
}
mTrustManager.reportUserMayRequestUnlock(KeyguardUpdateMonitor.getCurrentUser());
@@ -2359,7 +2367,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
if (allowRequest && shouldTriggerActiveUnlock()) {
- if (DEBUG) {
+ if (DEBUG_ACTIVE_UNLOCK) {
Log.d("ActiveUnlock", "reportUserRequestedUnlock"
+ " origin=" + requestOrigin.name()
+ " reason=" + reason
@@ -2777,8 +2785,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
private boolean isUnlockWithFingerprintPossible(int userId) {
- return mFpm != null && mFpm.isHardwareDetected() && !isFingerprintDisabled(userId)
- && mFpm.hasEnrolledTemplates(userId);
+ mIsUnlockWithFingerprintPossible.put(userId, mFpm != null && mFpm.isHardwareDetected()
+ && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId));
+ return mIsUnlockWithFingerprintPossible.get(userId);
+ }
+
+ /**
+ * Cached value for whether fingerprint is enrolled and possible to use for authentication.
+ * Note: checking fingerprint enrollment directly with the AuthController requires an IPC.
+ */
+ public boolean getCachedIsUnlockWithFingerprintPossible(int userId) {
+ return mIsUnlockWithFingerprintPossible.get(userId);
}
private boolean isUnlockWithFacePossible(int userId) {
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index e1913657b7cc..fdde40296511 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -55,7 +55,7 @@ public class LockIconView extends FrameLayout implements Dumpable {
@NonNull private final RectF mSensorRect;
@NonNull private PointF mLockIconCenter = new PointF(0f, 0f);
- private int mRadius;
+ private float mRadius;
private int mLockIconPadding;
private ImageView mLockIcon;
@@ -126,7 +126,7 @@ public class LockIconView extends FrameLayout implements Dumpable {
* Set the location of the lock icon.
*/
@VisibleForTesting
- public void setCenterLocation(@NonNull PointF center, int radius, int drawablePadding) {
+ public void setCenterLocation(@NonNull PointF center, float radius, int drawablePadding) {
mLockIconCenter = center;
mRadius = radius;
mLockIconPadding = drawablePadding;
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 2b217f02e834..d79b1454514e 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -188,6 +188,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
protected void onViewAttached() {
updateIsUdfpsEnrolled();
updateConfiguration();
+ updateLockIconLocation();
updateKeyguardShowing();
mUserUnlockedWithBiometric = false;
@@ -340,20 +341,17 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mHeightPixels = bounds.bottom;
mBottomPaddingPx = getResources().getDimensionPixelSize(R.dimen.lock_icon_margin_bottom);
- final int defaultPaddingPx =
- getResources().getDimensionPixelSize(R.dimen.lock_icon_padding);
- mScaledPaddingPx = (int) (defaultPaddingPx * mAuthController.getScaleFactor());
-
mUnlockedLabel = mView.getContext().getResources().getString(
R.string.accessibility_unlock_button);
mLockedLabel = mView.getContext()
.getResources().getString(R.string.accessibility_lock_icon);
-
- updateLockIconLocation();
}
private void updateLockIconLocation() {
if (mUdfpsSupported) {
+ final int defaultPaddingPx =
+ getResources().getDimensionPixelSize(R.dimen.lock_icon_padding);
+ mScaledPaddingPx = (int) (defaultPaddingPx * mAuthController.getScaleFactor());
mView.setCenterLocation(mAuthController.getUdfpsLocation(),
mAuthController.getUdfpsRadius(), mScaledPaddingPx);
} else {
@@ -362,8 +360,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mHeightPixels - mBottomPaddingPx - sLockIconRadiusPx),
sLockIconRadiusPx, mScaledPaddingPx);
}
-
- mView.getHitRect(mSensorTouchLocation);
}
@Override
@@ -386,6 +382,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen);
pw.println(" mStatusBarState: " + StatusBarState.toString(mStatusBarState));
pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount);
+ pw.println(" mSensorTouchLocation: " + mSensorTouchLocation);
if (mView != null) {
mView.dump(pw, args);
@@ -672,6 +669,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
}
private boolean inLockIconArea(MotionEvent event) {
+ mView.getHitRect(mSensorTouchLocation);
return mSensorTouchLocation.contains((int) event.getX(), (int) event.getY())
&& mView.getVisibility() == View.VISIBLE;
}
@@ -692,6 +690,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mExecutor.execute(() -> {
updateIsUdfpsEnrolled();
updateConfiguration();
+ updateLockIconLocation();
});
}
@@ -705,6 +704,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
public void onEnrollmentsChanged() {
updateUdfpsConfig();
}
+
+ @Override
+ public void onUdfpsLocationChanged() {
+ updateLockIconLocation();
+ }
};
private final View.OnClickListener mA11yClickListener = v -> onLongPress();
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index cbce854e4a71..dd312186afee 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -47,6 +47,7 @@ import android.hardware.graphics.common.AlphaInterpretation;
import android.hardware.graphics.common.DisplayDecorationSupport;
import android.os.Handler;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.util.DisplayUtils;
@@ -1067,15 +1068,22 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
}
private void updateLayoutParams() {
- if (mOverlays == null) {
- return;
+ //ToDo: We should skip unnecessary call to update view layout.
+ Trace.beginSection("ScreenDecorations#updateLayoutParams");
+ if (mScreenDecorHwcWindow != null) {
+ mWindowManager.updateViewLayout(mScreenDecorHwcWindow, getHwcWindowLayoutParams());
}
- for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
- if (mOverlays[i] == null) {
- continue;
+
+ if (mOverlays != null) {
+ for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
+ if (mOverlays[i] == null) {
+ continue;
+ }
+ mWindowManager.updateViewLayout(
+ mOverlays[i].getRootView(), getWindowLayoutParams(i));
}
- mWindowManager.updateViewLayout(mOverlays[i].getRootView(), getWindowLayoutParams(i));
}
+ Trace.endSection();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 932489372872..75339aaa843d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -79,6 +79,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import javax.inject.Inject;
@@ -446,11 +447,11 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
/**
* @return the radius of UDFPS on the screen in pixels
*/
- public int getUdfpsRadius() {
+ public float getUdfpsRadius() {
if (mUdfpsController == null || mUdfpsBounds == null) {
return -1;
}
- return mUdfpsBounds.height() / 2;
+ return mUdfpsBounds.height() / 2f;
}
/**
@@ -634,11 +635,17 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
displayInfo.getNaturalHeight());
final FingerprintSensorPropertiesInternal udfpsProp = mUdfpsProps.get(0);
+ final Rect previousUdfpsBounds = mUdfpsBounds;
mUdfpsBounds = udfpsProp.getLocation().getRect();
mUdfpsBounds.scale(scaleFactor);
mUdfpsController.updateOverlayParams(udfpsProp.sensorId,
new UdfpsOverlayParams(mUdfpsBounds, displayInfo.getNaturalWidth(),
displayInfo.getNaturalHeight(), scaleFactor, displayInfo.rotation));
+ if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds)) {
+ for (Callback cb : mCallbacks) {
+ cb.onUdfpsLocationChanged();
+ }
+ }
}
}
@@ -1054,5 +1061,10 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
* Called when the biometric prompt is no longer showing.
*/
default void onBiometricPromptDismissed() {}
+
+ /**
+ * The location in pixels can change due to resolution changes.
+ */
+ default void onUdfpsLocationChanged() {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index d9aa1bae3c69..86e501670440 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -335,15 +335,17 @@ class AuthRippleController @Inject constructor(
updateSensorLocation()
}
- override fun onEnrollmentsChanged() {
+ override fun onUdfpsLocationChanged() {
+ updateUdfpsDependentParams()
+ updateSensorLocation()
}
}
private fun updateUdfpsDependentParams() {
authController.udfpsProps?.let {
if (it.size > 0) {
- udfpsRadius = it[0].location.sensorRadius.toFloat()
udfpsController = udfpsControllerProvider.get()
+ udfpsRadius = authController.udfpsRadius
if (mView.isAttachedToWindow) {
udfpsController?.addCallback(udfpsControllerCallback)
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 74044e2c2eb8..1cc5df5d04cf 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -39,7 +39,6 @@ import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeMachine.State;
import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.Assert;
@@ -94,7 +93,6 @@ public class DozeTriggers implements DozeMachine.Part {
private final AuthController mAuthController;
private final DelayableExecutor mMainExecutor;
private final KeyguardStateController mKeyguardStateController;
- private final BatteryController mBatteryController;
private final UiEventLogger mUiEventLogger;
private final DevicePostureController mDevicePostureController;
@@ -186,8 +184,7 @@ public class DozeTriggers implements DozeMachine.Part {
@Main DelayableExecutor mainExecutor,
UiEventLogger uiEventLogger,
KeyguardStateController keyguardStateController,
- DevicePostureController devicePostureController,
- BatteryController batteryController) {
+ DevicePostureController devicePostureController) {
mContext = context;
mDozeHost = dozeHost;
mConfig = config;
@@ -208,7 +205,6 @@ public class DozeTriggers implements DozeMachine.Part {
mMainExecutor = mainExecutor;
mUiEventLogger = uiEventLogger;
mKeyguardStateController = keyguardStateController;
- mBatteryController = batteryController;
}
private final DevicePostureController.Callback mDevicePostureCallback =
posture -> {
@@ -320,12 +316,7 @@ public class DozeTriggers implements DozeMachine.Part {
gentleWakeUp(pulseReason);
} else if (isPickup) {
if (shouldDropPickupEvent()) {
- mDozeLog.traceSensorEventDropped(
- pulseReason,
- "keyguardOccluded="
- + mKeyguardStateController.isOccluded()
- + " pluggedInWireless="
- + mBatteryController.isPluggedInWireless());
+ mDozeLog.traceSensorEventDropped(pulseReason, "keyguard occluded");
return;
}
gentleWakeUp(pulseReason);
@@ -356,7 +347,7 @@ public class DozeTriggers implements DozeMachine.Part {
}
private boolean shouldDropPickupEvent() {
- return mKeyguardStateController.isOccluded() || mBatteryController.isPluggedInWireless();
+ return mKeyguardStateController.isOccluded();
}
private void gentleWakeUp(int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 82f935c7193f..626e185dec15 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -651,6 +651,10 @@ public class MediaControlPanel {
mIsArtworkBound = isArtworkBound;
}
+ // Scrim bounds are set manually so it scales as expected
+ albumView.getForeground().setBounds(0, 0,
+ Math.max(width, height), Math.max(width, height));
+
// Transition Colors to current color scheme
mColorSchemeTransition.updateColorScheme(colorScheme, mIsArtworkBound);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 83970dc15e61..629aa0317d24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -220,7 +220,7 @@ public class KeyguardClockPositionAlgorithm {
}
}
- public float getMinStackScrollerPadding() {
+ public float getLockscreenMinStackScrollerPadding() {
if (mBypassEnabled) {
return mUnlockedStackScrollerPadding;
} else if (mIsSplitShade) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 985df423d744..74b9c71d2198 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -24,6 +24,7 @@ import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
+import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
import static com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -325,6 +326,11 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mShouldUseSplitNotificationShade;
// The bottom padding reserved for elements of the keyguard measuring notifications
private float mKeyguardNotificationBottomPadding;
+ /**
+ * The top padding from where notification should start in lockscreen.
+ * Should be static also during animations and should match the Y of the first notification.
+ */
+ private float mKeyguardNotificationTopPadding;
// Current max allowed keyguard notifications determined by measuring the panel
private int mMaxAllowedKeyguardNotifications;
@@ -936,7 +942,7 @@ public class NotificationPanelViewController extends PanelViewController {
// the launcher icons animation starts, so use that as our
// duration.
.setDuration(unlockAnimationStartDelay)
- .setInterpolator(EMPHASIZED_DECELERATE)
+ .setInterpolator(EMPHASIZED_ACCELERATE)
.withEndAction(() -> {
instantCollapse();
mView.setAlpha(1f);
@@ -1513,7 +1519,10 @@ public class NotificationPanelViewController extends PanelViewController {
*/
@VisibleForTesting
float getSpaceForLockscreenNotifications() {
- float topPadding = mNotificationStackScrollLayoutController.getTopPadding();
+ float staticTopPadding = mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding()
+ // getMinStackScrollerPadding is from the top of the screen,
+ // but we need it from the top of the NSSL.
+ - mNotificationStackScrollLayoutController.getTop();
// Space between bottom of notifications and top of lock icon or udfps background.
float lockIconPadding = mLockIconViewController.getTop();
@@ -1525,11 +1534,15 @@ public class NotificationPanelViewController extends PanelViewController {
float bottomPadding = Math.max(lockIconPadding,
Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding));
+
mKeyguardNotificationBottomPadding = bottomPadding;
+ mKeyguardNotificationTopPadding = staticTopPadding;
+ // To debug the available space, enable debug lines in this class. If you change how the
+ // available space is calculated, please also update those lines.
float availableSpace =
mNotificationStackScrollLayoutController.getHeight()
- - topPadding
+ - staticTopPadding
- bottomPadding;
return availableSpace;
}
@@ -4923,6 +4936,20 @@ public class NotificationPanelViewController extends PanelViewController {
drawDebugInfo(canvas, (int) mLockIconViewController.getTop(), Color.GRAY,
"mLockIconViewController.getTop()");
+ if (mKeyguardShowing) {
+ // Notifications have the space between those two lines.
+ drawDebugInfo(canvas,
+ mNotificationStackScrollLayoutController.getTop() +
+ (int) mKeyguardNotificationTopPadding,
+ Color.RED,
+ "NSSL.getTop() + mKeyguardNotificationTopPadding");
+
+ drawDebugInfo(canvas, mNotificationStackScrollLayoutController.getBottom() -
+ (int) mKeyguardNotificationBottomPadding,
+ Color.RED,
+ "NSSL.getBottom() - mKeyguardNotificationBottomPadding");
+ }
+
mDebugPaint.setColor(Color.CYAN);
canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(),
mNotificationStackScrollLayoutController.getTopPadding(), mDebugPaint);
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index acff8712e92e..ebdddbf66091 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -180,7 +180,7 @@ public class QuickAccessWalletController {
int iconSizePx = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_icon_size);
GetWalletCardsRequest request =
new GetWalletCardsRequest(cardWidth, cardHeight, iconSizePx, /* maxCards= */ 1);
- mQuickAccessWalletClient.getWalletCards(mExecutor, request, cardsRetriever);
+ mQuickAccessWalletClient.getWalletCards(mCallbackExecutor, request, cardsRetriever);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
index 747649006b45..39cc34bb7e26 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
@@ -18,6 +18,7 @@ package com.android.keyguard
import android.content.ContentResolver
import android.database.ContentObserver
+import android.hardware.biometrics.BiometricFaceConstants
import android.net.Uri
import android.os.Handler
import android.os.UserHandle
@@ -44,18 +45,20 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
private val fakeWakeUri = Uri.Builder().appendPath("wake").build()
private val fakeUnlockIntentUri = Uri.Builder().appendPath("unlock-intent").build()
private val fakeBioFailUri = Uri.Builder().appendPath("bio-fail").build()
+ private val fakeFaceErrorsUri = Uri.Builder().appendPath("face-errors").build()
+ private val fakeFaceAcquiredUri = Uri.Builder().appendPath("face-acquired").build()
+ private val fakeUnlockIntentBioEnroll = Uri.Builder().appendPath("unlock-intent-bio").build()
@Mock
private lateinit var secureSettings: SecureSettings
-
@Mock
private lateinit var contentResolver: ContentResolver
-
@Mock
private lateinit var handler: Handler
-
@Mock
private lateinit var dumpManager: DumpManager
+ @Mock
+ private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Captor
private lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
@@ -72,6 +75,13 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
.thenReturn(fakeUnlockIntentUri)
`when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
.thenReturn(fakeBioFailUri)
+ `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS))
+ .thenReturn(fakeFaceErrorsUri)
+ `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO))
+ .thenReturn(fakeFaceAcquiredUri)
+ `when`(secureSettings.getUriFor(
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED))
+ .thenReturn(fakeUnlockIntentBioEnroll)
activeUnlockConfig = ActiveUnlockConfig(
handler,
@@ -99,12 +109,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
// WHEN unlock on wake is allowed
`when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
0, 0)).thenReturn(1)
- settingsObserverCaptor.value.onChange(
- false,
- listOf(fakeWakeUri),
- 0,
- 0
- )
+ updateSetting(fakeWakeUri)
// THEN active unlock triggers allowed on: wake, unlock-intent, and biometric failure
assertTrue(
@@ -134,12 +139,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
// WHEN unlock on biometric failed is allowed
`when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
0, 0)).thenReturn(1)
- settingsObserverCaptor.value.onChange(
- false,
- listOf(fakeUnlockIntentUri),
- 0,
- 0
- )
+ updateSetting(fakeUnlockIntentUri)
// THEN active unlock triggers allowed on: biometric failure ONLY
assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -154,19 +154,19 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
fun testOnBioFailSettingChanged() {
verifyRegisterSettingObserver()
- // GIVEN no active unlock settings enabled
+ // GIVEN no active unlock settings enabled and triggering unlock intent on biometric
+ // enrollment setting is disabled (empty string is disabled, null would use the default)
+ `when`(secureSettings.getStringForUser(
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ 0)).thenReturn("")
+ updateSetting(fakeUnlockIntentBioEnroll)
assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL))
// WHEN unlock on biometric failed is allowed
`when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
0, 0)).thenReturn(1)
- settingsObserverCaptor.value.onChange(
- false,
- listOf(fakeBioFailUri),
- 0,
- 0
- )
+ updateSetting(fakeBioFailUri)
// THEN active unlock triggers allowed on: biometric failure ONLY
assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -177,21 +177,146 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL))
}
- private fun verifyRegisterSettingObserver() {
- verify(contentResolver).registerContentObserver(
- eq(fakeWakeUri),
- eq(false),
- capture(settingsObserverCaptor),
- eq(UserHandle.USER_ALL))
+ @Test
+ fun testFaceErrorSettingsChanged() {
+ verifyRegisterSettingObserver()
- verify(contentResolver).registerContentObserver(
- eq(fakeUnlockIntentUri),
- eq(false),
- capture(settingsObserverCaptor),
- eq(UserHandle.USER_ALL))
+ // GIVEN unlock on biometric fail
+ `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
+ 0, 0)).thenReturn(1)
+ updateSetting(fakeBioFailUri)
+
+ // WHEN face error timeout (3), allow trigger active unlock
+ `when`(secureSettings.getStringForUser(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS,
+ 0)).thenReturn("3")
+ updateSetting(fakeFaceAcquiredUri)
+
+ // THEN active unlock triggers allowed on error TIMEOUT
+ assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceError(
+ BiometricFaceConstants.FACE_ERROR_TIMEOUT))
+
+ assertFalse(activeUnlockConfig.shouldRequestActiveUnlockOnFaceError(
+ BiometricFaceConstants.FACE_ERROR_CANCELED))
+ }
+
+ @Test
+ fun testFaceAcquiredSettingsChanged() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN unlock on biometric fail
+ `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
+ 0, 0)).thenReturn(1)
+ updateSetting(fakeBioFailUri)
+
+ // WHEN face acquiredMsg DARK_GLASSESand MOUTH_COVERING are allowed to trigger
+ `when`(secureSettings.getStringForUser(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
+ 0)).thenReturn(
+ "${BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED}" +
+ "|${BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED}")
+ updateSetting(fakeFaceAcquiredUri)
+
+ // THEN active unlock triggers allowed on acquired messages DARK_GLASSES & MOUTH_COVERING
+ assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
+ BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED))
+ assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
+ BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED))
+
+ assertFalse(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
+ BiometricFaceConstants.FACE_ACQUIRED_GOOD))
+ assertFalse(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
+ BiometricFaceConstants.FACE_ACQUIRED_NOT_DETECTED))
+ }
+
+ @Test
+ fun testTriggerOnUnlockIntentWhenBiometricEnrolledNone() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN unlock on biometric fail
+ `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
+ 0, 0)).thenReturn(1)
+ updateSetting(fakeBioFailUri)
+
+ // GIVEN fingerprint and face are NOT enrolled
+ activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
+ `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(false)
+ `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(false)
+
+ // WHEN unlock intent is allowed when NO biometrics are enrolled (0)
+ `when`(secureSettings.getStringForUser(
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ 0)).thenReturn("${ActiveUnlockConfig.BIOMETRIC_TYPE_NONE}")
+ updateSetting(fakeUnlockIntentBioEnroll)
+
+ // THEN active unlock triggers allowed on unlock intent
+ assertTrue(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT))
+ }
+
+ @Test
+ fun testTriggerOnUnlockIntentWhenBiometricEnrolledFingerprintOrFaceOnly() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN unlock on biometric fail
+ `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
+ 0, 0)).thenReturn(1)
+ updateSetting(fakeBioFailUri)
+
+ // GIVEN fingerprint and face are both enrolled
+ activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
+ `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true)
+ `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(true)
+
+ // WHEN unlock intent is allowed when ONLY fingerprint is enrolled or NO biometircs
+ // are enrolled
+ `when`(secureSettings.getStringForUser(
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ 0)).thenReturn(
+ "${ActiveUnlockConfig.BIOMETRIC_TYPE_ANY_FACE}" +
+ "|${ActiveUnlockConfig.BIOMETRIC_TYPE_ANY_FINGERPRINT}")
+ updateSetting(fakeUnlockIntentBioEnroll)
+
+ // THEN active unlock triggers NOT allowed on unlock intent
+ assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT))
+
+ // WHEN fingerprint ONLY enrolled
+ `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(false)
+ `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(true)
+
+ // THEN active unlock triggers allowed on unlock intent
+ assertTrue(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT))
+
+ // WHEN face ONLY enrolled
+ `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true)
+ `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(false)
+
+ // THEN active unlock triggers allowed on unlock intent
+ assertTrue(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT))
+ }
+
+ private fun updateSetting(uri: Uri) {
+ settingsObserverCaptor.value.onChange(
+ false,
+ listOf(uri),
+ 0,
+ 0 /* flags */
+ )
+ }
+
+ private fun verifyRegisterSettingObserver() {
+ verifyRegisterSettingObserver(fakeWakeUri)
+ verifyRegisterSettingObserver(fakeUnlockIntentUri)
+ verifyRegisterSettingObserver(fakeBioFailUri)
+ verifyRegisterSettingObserver(fakeFaceErrorsUri)
+ verifyRegisterSettingObserver(fakeFaceAcquiredUri)
+ verifyRegisterSettingObserver(fakeUnlockIntentBioEnroll)
+ }
+ private fun verifyRegisterSettingObserver(uri: Uri) {
verify(contentResolver).registerContentObserver(
- eq(fakeBioFailUri),
+ eq(uri),
eq(false),
capture(settingsObserverCaptor),
eq(UserHandle.USER_ALL))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index ae387e86de9d..4eeb4acf18b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -45,7 +45,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeTriggers.DozingUpdateUiEvent;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -91,8 +90,6 @@ public class DozeTriggersTest extends SysuiTestCase {
private KeyguardStateController mKeyguardStateController;
@Mock
private DevicePostureController mDevicePostureController;
- @Mock
- private BatteryController mBatteryController;
private DozeTriggers mTriggers;
private FakeSensorManager mSensors;
@@ -125,7 +122,7 @@ public class DozeTriggersTest extends SysuiTestCase {
asyncSensorManager, wakeLock, mDockManager, mProximitySensor,
mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher, new FakeSettings(),
mAuthController, mExecutor, mUiEventLogger, mKeyguardStateController,
- mDevicePostureController, mBatteryController);
+ mDevicePostureController);
mTriggers.setDozeMachine(mMachine);
waitForSensorManager();
}
@@ -233,9 +230,7 @@ public class DozeTriggersTest extends SysuiTestCase {
when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
// WHEN the pick up gesture is triggered and keyguard isn't occluded
- // and device isn't on a wireless charger
when(mKeyguardStateController.isOccluded()).thenReturn(false);
- when(mBatteryController.isPluggedInWireless()).thenReturn(false);
mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
// THEN wakeup
@@ -249,22 +244,6 @@ public class DozeTriggersTest extends SysuiTestCase {
// WHEN the pick up gesture is triggered and keyguard IS occluded
when(mKeyguardStateController.isOccluded()).thenReturn(true);
- when(mBatteryController.isPluggedInWireless()).thenReturn(false);
- mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
-
- // THEN never wakeup
- verify(mMachine, never()).wakeUp();
- }
-
- @Test
- public void testPickupGestureWirelessCharger() {
- // GIVEN device is in doze (screen blank, but running doze sensors)
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-
- // WHEN the pick up gesture is triggered
- // and device IS on a wireless charger
- when(mKeyguardStateController.isOccluded()).thenReturn(false);
- when(mBatteryController.isPluggedInWireless()).thenReturn(true);
mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
// THEN never wakeup
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index 5ff316e2efec..c532ed5ab651 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -34,8 +34,6 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.AnimatedStateListDrawable;
import android.hardware.biometrics.BiometricSourceType;
-import android.hardware.biometrics.SensorLocationInternal;
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Pair;
@@ -77,9 +75,6 @@ import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
-import java.util.ArrayList;
-import java.util.List;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -182,7 +177,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
@Test
public void testUpdateFingerprintLocationOnInit() {
// GIVEN fp sensor location is available pre-attached
- Pair<Integer, PointF> udfps = setupUdfps(); // first = radius, second = udfps location
+ Pair<Float, PointF> udfps = setupUdfps(); // first = radius, second = udfps location
// WHEN lock icon view controller is initialized and attached
mLockIconViewController.init();
@@ -197,7 +192,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
@Test
public void testUpdatePaddingBasedOnResolutionScale() {
// GIVEN fp sensor location is available pre-attached & scaled resolution factor is 5
- Pair<Integer, PointF> udfps = setupUdfps(); // first = radius, second = udfps location
+ Pair<Float, PointF> udfps = setupUdfps(); // first = radius, second = udfps location
when(mAuthController.getScaleFactor()).thenReturn(5f);
// WHEN lock icon view controller is initialized and attached
@@ -215,20 +210,19 @@ public class LockIconViewControllerTest extends SysuiTestCase {
// GIVEN fp sensor location is not available pre-init
when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false);
when(mAuthController.getFingerprintSensorLocation()).thenReturn(null);
- when(mAuthController.getUdfpsProps()).thenReturn(null);
mLockIconViewController.init();
captureAttachListener();
mAttachListener.onViewAttachedToWindow(mLockIconView);
- // GIVEN fp sensor location is available post-atttached
+ // GIVEN fp sensor location is available post-attached
captureAuthControllerCallback();
- Pair<Integer, PointF> udfps = setupUdfps();
+ Pair<Float, PointF> udfps = setupUdfps();
// WHEN all authenticators are registered
mAuthControllerCallback.onAllAuthenticatorsRegistered();
mDelayableExecutor.runAllReady();
- // THEN lock icon view location is updated with the same coordinates as fpProps
+ // THEN lock icon view location is updated with the same coordinates as auth controller vals
verify(mLockIconView).setCenterLocation(eq(udfps.second), eq(udfps.first),
eq(PADDING));
}
@@ -402,21 +396,10 @@ public class LockIconViewControllerTest extends SysuiTestCase {
verify(mLockIconView).setTranslationX(0);
}
- private Pair<Integer, PointF> setupUdfps() {
+ private Pair<Float, PointF> setupUdfps() {
when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true);
final PointF udfpsLocation = new PointF(50, 75);
- final int radius = 33;
- final FingerprintSensorPropertiesInternal fpProps =
- new FingerprintSensorPropertiesInternal(
- /* sensorId */ 0,
- /* strength */ 0,
- /* max enrollments per user */ 5,
- /* component info */ new ArrayList<>(),
- /* sensorType */ 3,
- /* halControlsIllumination */ true,
- /* resetLockoutRequiresHwToken */ false,
- List.of(new SensorLocationInternal("" /* displayId */,
- (int) udfpsLocation.x, (int) udfpsLocation.y, radius)));
+ final float radius = 33f;
when(mAuthController.getUdfpsLocation()).thenReturn(udfpsLocation);
when(mAuthController.getUdfpsRadius()).thenReturn(radius);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 63a0de8578d7..1310d69d0d0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -21,7 +21,6 @@ import android.animation.AnimatorSet
import android.app.PendingIntent
import android.app.smartspace.SmartspaceAction
import android.content.Context
-import org.mockito.Mockito.`when` as whenever
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
@@ -67,8 +66,8 @@ import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.KotlinArgumentCaptor
-import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.withArgCaptor
@@ -92,6 +91,7 @@ import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
private const val KEY = "TEST_KEY"
private const val PACKAGE = "PKG"
@@ -339,6 +339,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(viewHolder.player).thenReturn(view)
whenever(viewHolder.appIcon).thenReturn(appIcon)
whenever(viewHolder.albumView).thenReturn(albumView)
+ whenever(albumView.foreground).thenReturn(mock(Drawable::class.java))
whenever(viewHolder.titleText).thenReturn(titleText)
whenever(viewHolder.artistText).thenReturn(artistText)
whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 6d3a5fecc826..ec20271ea43b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -336,7 +336,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
// WHEN the position algorithm is run
positionClock();
// THEN the padding DOESN'T adjust for keyguard status height.
- assertThat(mClockPositionAlgorithm.getMinStackScrollerPadding())
+ assertThat(mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding())
.isEqualTo(mKeyguardStatusBarHeaderHeight);
}
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 94e6b9a12a93..11f96cec6369 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
@@ -610,13 +610,13 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
when(mLockIconViewController.getTop()).thenReturn(80f);
when(mResources.getDimensionPixelSize(R.dimen.shelf_and_lock_icon_overlap)).thenReturn(5);
- // Available space (100 - 10 - 15 = 75)
+ // Available space (100 - 0 - 15 = 85)
when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(100);
- when(mNotificationStackScrollLayoutController.getTopPadding()).thenReturn(10);
+ when(mNotificationStackScrollLayoutController.getTop()).thenReturn(0);
mNotificationPanelViewController.updateResources();
assertThat(mNotificationPanelViewController.getSpaceForLockscreenNotifications())
- .isEqualTo(75);
+ .isEqualTo(85);
}
@Test
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 649328d1eef3..9b29bae1fc46 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -242,6 +242,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
int getCurrentUserIdLocked();
+ Pair<float[], MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
+ int windowId);
+
boolean isAccessibilityButtonShown();
/**
@@ -551,8 +554,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int resolvedWindowId;
RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
- final MagnificationSpec spec;
- final float[] transformMatrix;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!hasRightsToCurrentUserLocked()) {
@@ -576,11 +577,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
partialInteractiveRegion.recycle();
partialInteractiveRegion = null;
}
- final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
- getTransformMatrixAndSpecLocked(resolvedWindowId);
- transformMatrix = transformMatrixAndSpec.first;
- spec = transformMatrixAndSpec.second;
}
+ final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+ getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
+ final float[] transformMatrix = transformMatrixAndSpec.first;
+ final MagnificationSpec spec = transformMatrixAndSpec.second;
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
@@ -628,8 +629,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int resolvedWindowId;
RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
- final MagnificationSpec spec;
- final float [] transformMatrix;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!hasRightsToCurrentUserLocked()) {
@@ -653,11 +652,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
partialInteractiveRegion.recycle();
partialInteractiveRegion = null;
}
- final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
- getTransformMatrixAndSpecLocked(resolvedWindowId);
- transformMatrix = transformMatrixAndSpec.first;
- spec = transformMatrixAndSpec.second;
}
+ final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+ getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
+ final float[] transformMatrix = transformMatrixAndSpec.first;
+ final MagnificationSpec spec = transformMatrixAndSpec.second;
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
@@ -706,8 +705,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int resolvedWindowId;
RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
- final MagnificationSpec spec;
- final float[] transformMatrix;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!hasRightsToCurrentUserLocked()) {
@@ -731,11 +728,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
partialInteractiveRegion.recycle();
partialInteractiveRegion = null;
}
- final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
- getTransformMatrixAndSpecLocked(resolvedWindowId);
- transformMatrix = transformMatrixAndSpec.first;
- spec = transformMatrixAndSpec.second;
}
+ final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+ getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
+ final float[] transformMatrix = transformMatrixAndSpec.first;
+ final MagnificationSpec spec = transformMatrixAndSpec.second;
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
@@ -786,8 +783,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int resolvedWindowId;
RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
- final MagnificationSpec spec;
- final float[] transformMatrix;
synchronized (mLock) {
if (!hasRightsToCurrentUserLocked()) {
return null;
@@ -811,11 +806,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
partialInteractiveRegion.recycle();
partialInteractiveRegion = null;
}
- final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
- getTransformMatrixAndSpecLocked(resolvedWindowId);
- transformMatrix = transformMatrixAndSpec.first;
- spec = transformMatrixAndSpec.second;
}
+ final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+ getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
+ final float[] transformMatrix = transformMatrixAndSpec.first;
+ final MagnificationSpec spec = transformMatrixAndSpec.second;
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
@@ -865,8 +860,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int resolvedWindowId;
RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
- final MagnificationSpec spec;
- final float[] transformMatrix;
synchronized (mLock) {
if (!hasRightsToCurrentUserLocked()) {
return null;
@@ -889,12 +882,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
partialInteractiveRegion.recycle();
partialInteractiveRegion = null;
}
-
- final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
- getTransformMatrixAndSpecLocked(resolvedWindowId);
- transformMatrix = transformMatrixAndSpec.first;
- spec = transformMatrixAndSpec.second;
}
+ final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+ getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
+ final float[] transformMatrix = transformMatrixAndSpec.first;
+ final MagnificationSpec spec = transformMatrixAndSpec.second;
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
@@ -1672,21 +1664,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
mInvocationHandler.startInputLocked(connection, editorInfo, restarting);
}
-
-
@Nullable
- Pair<float[], MagnificationSpec> getTransformMatrixAndSpecLocked(int resolvedWindowId) {
- final WindowInfo windowInfo =
- mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId);
- if (windowInfo == null) {
- Slog.w(LOG_TAG, "getTransformMatrixAndSpec, windowInfo is null window id = "
- + resolvedWindowId);
- return new Pair<>(null, null);
- }
-
- final MagnificationSpec spec = new MagnificationSpec();
- spec.setTo(windowInfo.mMagnificationSpec);
- return new Pair<>(windowInfo.mTransformMatrix, spec);
+ private Pair<float[], MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
+ int resolvedWindowId) {
+ return mSystemSupport.getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 4806514a0e13..99c849527034 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -68,6 +68,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
@@ -99,6 +100,7 @@ import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArraySet;
import android.util.IntArray;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -458,6 +460,41 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
@Override
+ public Pair<float[], MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
+ int windowId) {
+ WindowInfo windowInfo;
+ synchronized (mLock) {
+ windowInfo = mA11yWindowManager.findWindowInfoByIdLocked(windowId);
+ }
+ if (windowInfo != null) {
+ final MagnificationSpec spec = new MagnificationSpec();
+ spec.setTo(windowInfo.mMagnificationSpec);
+ return new Pair<>(windowInfo.mTransformMatrix, spec);
+ } else {
+ // If the framework doesn't track windows, we fall back to get the pair of
+ // transformation matrix and MagnificationSpe from the WindowManagerService's
+ // WindowState.
+ IBinder token;
+ synchronized (mLock) {
+ token = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(mCurrentUserId,
+ windowId);
+ }
+ Pair<Matrix, MagnificationSpec> pair =
+ mWindowManagerService.getWindowTransformationMatrixAndMagnificationSpec(token);
+ final float[] outTransformationMatrix = new float[9];
+ final Matrix tmpMatrix = pair.first;
+ final MagnificationSpec spec = pair.second;
+ if (!spec.isNop()) {
+ tmpMatrix.postScale(spec.scale, spec.scale);
+ tmpMatrix.postTranslate(spec.offsetX, spec.offsetY);
+ }
+ tmpMatrix.getValues(outTransformationMatrix);
+
+ return new Pair<>(outTransformationMatrix, pair.second);
+ }
+ }
+
+ @Override
public void onServiceInfoChangedLocked(AccessibilityUserState userState) {
mSecurityPolicy.onBoundServicesChangedLocked(userState.mUserId,
userState.mBoundServices);
@@ -3750,12 +3787,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
boundsInScreenBeforeMagnification.centerY());
// Invert magnification if needed.
- final WindowInfo windowInfo = mA11yWindowManager.findWindowInfoByIdLocked(
- focus.getWindowId());
+ final Pair<float[], MagnificationSpec> pair =
+ getWindowTransformationMatrixAndMagnificationSpec(focus.getWindowId());
MagnificationSpec spec = null;
- if (windowInfo != null) {
+ if (pair != null && pair.second != null) {
spec = new MagnificationSpec();
- spec.setTo(windowInfo.mMagnificationSpec);
+ spec.setTo(pair.second);
}
if (spec != null && !spec.isNop()) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 8e32a7a8e255..6d3620fa2ee6 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -3225,10 +3225,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN);
mService.logDatasetShown(id, mClientState, UI_TYPE_DIALOG);
}
+ // Just show fill dialog once, so disabled after shown.
+ // Note: Cannot disable before requestShowFillDialog() because the method
+ // need to check whether fill dialog enabled.
+ setFillDialogDisabled();
return;
} else {
setFillDialogDisabled();
}
+
}
if (response.supportsInlineSuggestions()) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 62bb9f155c34..3b11038daf7e 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -732,9 +732,12 @@ public class CompanionDeviceManagerService extends SystemService {
String[] args, ShellCallback callback, ResultReceiver resultReceiver)
throws RemoteException {
enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand");
- new CompanionDeviceShellCommand(
- CompanionDeviceManagerService.this, mAssociationStore)
- .exec(this, in, out, err, args, callback, resultReceiver);
+
+ final CompanionDeviceShellCommand cmd = new CompanionDeviceShellCommand(
+ CompanionDeviceManagerService.this,
+ mAssociationStore,
+ mDevicePresenceMonitor);
+ cmd.exec(this, in, out, err, args, callback, resultReceiver);
}
@Override
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index fd130852a43a..6a19a42723c5 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -21,6 +21,8 @@ import android.os.ShellCommand;
import android.util.Log;
import android.util.Slog;
+import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+
import java.io.PrintWriter;
import java.util.List;
@@ -29,20 +31,24 @@ class CompanionDeviceShellCommand extends ShellCommand {
private final CompanionDeviceManagerService mService;
private final AssociationStore mAssociationStore;
+ private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
CompanionDeviceShellCommand(CompanionDeviceManagerService service,
- AssociationStore associationStore) {
+ AssociationStore associationStore,
+ CompanionDevicePresenceMonitor devicePresenceMonitor) {
mService = service;
mAssociationStore = associationStore;
+ mDevicePresenceMonitor = devicePresenceMonitor;
}
@Override
public int onCommand(String cmd) {
final PrintWriter out = getOutPrintWriter();
+ final int associationId;
try {
switch (cmd) {
case "list": {
- final int userId = getNextArgInt();
+ final int userId = getNextIntArgRequired();
final List<AssociationInfo> associationsForUser =
mAssociationStore.getAssociationsForUser(userId);
for (AssociationInfo association : associationsForUser) {
@@ -55,7 +61,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
break;
case "associate": {
- int userId = getNextArgInt();
+ int userId = getNextIntArgRequired();
String packageName = getNextArgRequired();
String address = getNextArgRequired();
mService.legacyCreateAssociation(userId, address, packageName, null);
@@ -63,7 +69,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
break;
case "disassociate": {
- final int userId = getNextArgInt();
+ final int userId = getNextIntArgRequired();
final String packageName = getNextArgRequired();
final String address = getNextArgRequired();
final AssociationInfo association =
@@ -80,6 +86,16 @@ class CompanionDeviceShellCommand extends ShellCommand {
}
break;
+ case "simulate-device-appeared":
+ associationId = getNextIntArgRequired();
+ mDevicePresenceMonitor.simulateDeviceAppeared(associationId);
+ break;
+
+ case "simulate-device-disappeared":
+ associationId = getNextIntArgRequired();
+ mDevicePresenceMonitor.simulateDeviceDisappeared(associationId);
+ break;
+
default:
return handleDefaultCommands(cmd);
}
@@ -91,10 +107,6 @@ class CompanionDeviceShellCommand extends ShellCommand {
}
}
- private int getNextArgInt() {
- return Integer.parseInt(getNextArgRequired());
- }
-
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -108,7 +120,31 @@ class CompanionDeviceShellCommand extends ShellCommand {
pw.println(" disassociate USER_ID PACKAGE MAC_ADDRESS");
pw.println(" Remove an existing Association.");
pw.println(" clear-association-memory-cache");
- pw.println(" Clear the in-memory association cache and reload all association "
- + "information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY.");
+ pw.println(" Clear the in-memory association cache and reload all association ");
+ pw.println(" information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY.");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+
+ pw.println(" simulate-device-appeared ASSOCIATION_ID");
+ pw.println(" Make CDM act as if the given companion device has appeared.");
+ pw.println(" I.e. bind the associated companion application's");
+ pw.println(" CompanionDeviceService(s) and trigger onDeviceAppeared() callback.");
+ pw.println(" The CDM will consider the devices as present for 60 seconds and then");
+ pw.println(" will act as if device disappeared, unless 'simulate-device-disappeared'");
+ pw.println(" or 'simulate-device-appeared' is called again before 60 seconds run out"
+ + ".");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+
+ pw.println(" simulate-device-disappeared ASSOCIATION_ID");
+ pw.println(" Make CDM act as if the given companion device has disappeared.");
+ pw.println(" I.e. unbind the associated companion application's");
+ pw.println(" CompanionDeviceService(s) and trigger onDeviceDisappeared() callback.");
+ pw.println(" NOTE: This will only have effect if 'simulate-device-appeared' was");
+ pw.println(" invoked for the same device (same ASSOCIATION_ID) no longer than");
+ pw.println(" 60 seconds ago.");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+ }
+
+ private int getNextIntArgRequired() {
+ return Integer.parseInt(getNextArgRequired());
}
}
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index 24be1b6fd701..37e83697c787 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -16,11 +16,19 @@
package com.android.server.companion.presence;
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SHELL_UID;
+
import android.annotation.NonNull;
import android.annotation.SuppressLint;
+import android.annotation.TestApi;
import android.bluetooth.BluetoothAdapter;
import android.companion.AssociationInfo;
import android.content.Context;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.util.Log;
import com.android.server.companion.AssociationStore;
@@ -72,6 +80,11 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
private final @NonNull Set<Integer> mNearbyBleDevices = new HashSet<>();
private final @NonNull Set<Integer> mReportedSelfManagedDevices = new HashSet<>();
+ // Tracking "simulated" presence. Used for debugging and testing only.
+ private final @NonNull Set<Integer> mSimulated = new HashSet<>();
+ private final SimulatedDevicePresenceSchedulerHelper mSchedulerHelper =
+ new SimulatedDevicePresenceSchedulerHelper();
+
public CompanionDevicePresenceMonitor(@NonNull AssociationStore associationStore,
@NonNull Callback callback) {
mAssociationStore = associationStore;
@@ -106,7 +119,8 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
public boolean isDevicePresent(int associationId) {
return mReportedSelfManagedDevices.contains(associationId)
|| mConnectedBtDevices.contains(associationId)
- || mNearbyBleDevices.contains(associationId);
+ || mNearbyBleDevices.contains(associationId)
+ || mSimulated.contains(associationId);
}
/**
@@ -155,6 +169,45 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
onDeviceGone(mNearbyBleDevices, associationId, /* sourceLoggingTag */ "ble");
}
+ /** FOR DEBUGGING AND/OR TESTING PURPOSES ONLY. */
+ @TestApi
+ public void simulateDeviceAppeared(int associationId) {
+ // IMPORTANT: this API should only be invoked via the
+ // 'companiondevice simulate-device-appeared' Shell command, so the only uid-s allowed to
+ // make this call are SHELL and ROOT.
+ // No other caller (including SYSTEM!) should be allowed.
+ enforceCallerShellOrRoot();
+ // Make sure the association exists.
+ enforceAssociationExists(associationId);
+
+ onDevicePresent(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+
+ mSchedulerHelper.scheduleOnDeviceGoneCallForSimulatedDevicePresence(associationId);
+ }
+
+ /** FOR DEBUGGING AND/OR TESTING PURPOSES ONLY. */
+ @TestApi
+ public void simulateDeviceDisappeared(int associationId) {
+ // IMPORTANT: this API should only be invoked via the
+ // 'companiondevice simulate-device-appeared' Shell command, so the only uid-s allowed to
+ // make this call are SHELL and ROOT.
+ // No other caller (including SYSTEM!) should be allowed.
+ enforceCallerShellOrRoot();
+ // Make sure the association exists.
+ enforceAssociationExists(associationId);
+
+ mSchedulerHelper.unscheduleOnDeviceGoneCallForSimulatedDevicePresence(associationId);
+
+ onDeviceGone(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+ }
+
+ private void enforceAssociationExists(int associationId) {
+ if (mAssociationStore.getAssociationById(associationId) == null) {
+ throw new IllegalArgumentException(
+ "Association with id " + associationId + " does not exist.");
+ }
+ }
+
private void onDevicePresent(@NonNull Set<Integer> presentDevicesForSource,
int newDeviceAssociationId, @NonNull String sourceLoggingTag) {
if (DEBUG) {
@@ -212,6 +265,7 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
mConnectedBtDevices.remove(associationId);
mNearbyBleDevices.remove(associationId);
mReportedSelfManagedDevices.remove(associationId);
+ mSimulated.remove(associationId);
}
/**
@@ -232,4 +286,36 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
// CompanionDeviceManagerService will know that the association is removed, and will do
// what's needed.
}
+
+ private static void enforceCallerShellOrRoot() {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid == SHELL_UID || callingUid == ROOT_UID) return;
+
+ throw new SecurityException("Caller is neither Shell nor Root");
+ }
+
+ private class SimulatedDevicePresenceSchedulerHelper extends Handler {
+ SimulatedDevicePresenceSchedulerHelper() {
+ super(Looper.getMainLooper());
+ }
+
+ void scheduleOnDeviceGoneCallForSimulatedDevicePresence(int associationId) {
+ // First, unschedule if it was scheduled previously.
+ if (hasMessages(/* what */ associationId)) {
+ removeMessages(/* what */ associationId);
+ }
+
+ sendEmptyMessageDelayed(/* what */ associationId, 60 * 1000 /* 60 seconds */);
+ }
+
+ void unscheduleOnDeviceGoneCallForSimulatedDevicePresence(int associationId) {
+ removeMessages(/* what */ associationId);
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ final int associationId = msg.what;
+ onDeviceGone(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/DropboxRateLimiter.java b/services/core/java/com/android/server/am/DropboxRateLimiter.java
index 18fb6a480f29..08a6719a016a 100644
--- a/services/core/java/com/android/server/am/DropboxRateLimiter.java
+++ b/services/core/java/com/android/server/am/DropboxRateLimiter.java
@@ -24,9 +24,14 @@ import com.android.internal.annotations.GuardedBy;
/** Rate limiter for adding errors into dropbox. */
public class DropboxRateLimiter {
- private static final long RATE_LIMIT_BUFFER_EXPIRY = 15 * DateUtils.SECOND_IN_MILLIS;
- private static final long RATE_LIMIT_BUFFER_DURATION = 10 * DateUtils.SECOND_IN_MILLIS;
- private static final int RATE_LIMIT_ALLOWED_ENTRIES = 5;
+ // After RATE_LIMIT_ALLOWED_ENTRIES have been collected (for a single breakdown of
+ // process/eventType) further entries will be rejected until RATE_LIMIT_BUFFER_DURATION has
+ // elapsed, after which the current count for this breakdown will be reset.
+ private static final long RATE_LIMIT_BUFFER_DURATION = 10 * DateUtils.MINUTE_IN_MILLIS;
+ // The time duration after which the rate limit buffer will be cleared.
+ private static final long RATE_LIMIT_BUFFER_EXPIRY = 3 * RATE_LIMIT_BUFFER_DURATION;
+ // The number of entries to keep per breakdown of process/eventType.
+ private static final int RATE_LIMIT_ALLOWED_ENTRIES = 6;
@GuardedBy("mErrorClusterRecords")
private final ArrayMap<String, ErrorRecord> mErrorClusterRecords = new ArrayMap<>();
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index fc73a5955001..cceacd8c6fa3 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2792,6 +2792,15 @@ public final class ProcessList {
}
int N = procs.size();
+ for (int i = 0; i < N; ++i) {
+ final ProcessRecord proc = procs.get(i).first;
+ try {
+ Process.setProcessFrozen(proc.getPid(), proc.uid, true);
+ } catch (Exception e) {
+ Slog.w(TAG, "Unable to freeze " + proc.getPid() + " " + proc.processName);
+ }
+ }
+
for (int i=0; i<N; i++) {
final Pair<ProcessRecord, Boolean> proc = procs.get(i);
removeProcessLocked(proc.first, callerWillRestart, allowRestart || proc.second,
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 122a950e4fd3..d8aa9aa6591e 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -486,8 +486,7 @@ public class SpatializerHelper {
for (SADeviceState deviceState : mSADevices) {
if (deviceType == deviceState.mDeviceType
- && (wireless && ada.getAddress().equals(deviceState.mDeviceAddress))
- || !wireless) {
+ && (!wireless || ada.getAddress().equals(deviceState.mDeviceAddress))) {
isInList = true;
if (forceEnable) {
deviceState.mEnabled = true;
@@ -511,8 +510,7 @@ public class SpatializerHelper {
for (SADeviceState deviceState : mSADevices) {
if (deviceType == deviceState.mDeviceType
- && (wireless && ada.getAddress().equals(deviceState.mDeviceAddress))
- || !wireless) {
+ && (!wireless || ada.getAddress().equals(deviceState.mDeviceAddress))) {
deviceState.mEnabled = false;
break;
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 5ae3f337d0a5..e4e9d1d49a6e 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1712,6 +1712,13 @@ public class InputManagerService extends IInputManager.Stub
mPointerIconDisplayContext = null;
}
+ synchronized (mAdditionalDisplayInputPropertiesLock) {
+ setPointerIconVisible(AdditionalDisplayInputProperties.DEFAULT_POINTER_ICON_VISIBLE,
+ displayId);
+ setPointerAcceleration(AdditionalDisplayInputProperties.DEFAULT_POINTER_ACCELERATION,
+ displayId);
+ }
+
mNative.displayRemoved(displayId);
}
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index db17c1056e39..8180e66166d9 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -64,7 +64,9 @@ final class HandwritingEventReceiverSurface {
| InputConfig.INTERCEPTS_STYLUS
| InputConfig.TRUSTED_OVERLAY;
- // The touchable region of this input surface is not initially configured.
+ // Configure the surface to receive stylus events across the entire display.
+ mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
+
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setInputWindowInfo(mInputSurface, mWindowHandle);
t.setLayer(mInputSurface, HANDWRITING_SURFACE_LAYER);
@@ -81,10 +83,6 @@ final class HandwritingEventReceiverSurface {
mWindowHandle.ownerUid = imeUid;
mWindowHandle.inputConfig &= ~InputConfig.SPY;
- // Update the touchable region so that the IME can intercept stylus events
- // across the entire display.
- mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
-
new SurfaceControl.Transaction()
.setInputWindowInfo(mInputSurface, mWindowHandle)
.apply();
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
index a70677222506..f89b6aedf1f5 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
@@ -91,7 +91,7 @@ final class HandwritingModeController {
* InputEventReceiver that batches events according to the current thread's Choreographer.
*/
@UiThread
- void initializeHandwritingSpy(int displayId, IBinder focusedWindowToken) {
+ void initializeHandwritingSpy(int displayId) {
// When resetting, reuse resources if we are reinitializing on the same display.
reset(displayId == mCurrentDisplayId);
mCurrentDisplayId = displayId;
@@ -115,12 +115,6 @@ final class HandwritingModeController {
mHandwritingSurface = new HandwritingEventReceiverSurface(
name, displayId, surface, channel);
- // Configure the handwriting window to receive events over the focused window's bounds.
- mWindowManagerInternal.replaceInputSurfaceTouchableRegionWithWindowCrop(
- mHandwritingSurface.getSurface(),
- mHandwritingSurface.getInputWindowHandle(),
- focusedWindowToken);
-
// Use a dup of the input channel so that event processing can be paused by disposing the
// event receiver without causing a fd hangup.
mHandwritingEventReceiver = new BatchedInputEventReceiver.SimpleBatchedInputEventReceiver(
@@ -149,7 +143,8 @@ final class HandwritingModeController {
*/
@UiThread
@Nullable
- HandwritingSession startHandwritingSession(int requestId, int imePid, int imeUid) {
+ HandwritingSession startHandwritingSession(
+ int requestId, int imePid, int imeUid, IBinder focusedWindowToken) {
if (mHandwritingSurface == null) {
Slog.e(TAG, "Cannot start handwriting session: Handwriting was not initialized.");
return null;
@@ -158,12 +153,20 @@ final class HandwritingModeController {
Slog.e(TAG, "Cannot start handwriting session: Invalid request id: " + requestId);
return null;
}
- if (!mRecordingGesture) {
+ if (!mRecordingGesture || mHandwritingBuffer.isEmpty()) {
Slog.e(TAG, "Cannot start handwriting session: No stylus gesture is being recorded.");
return null;
}
Objects.requireNonNull(mHandwritingEventReceiver,
"Handwriting session was already transferred to IME.");
+ final MotionEvent downEvent = mHandwritingBuffer.get(0);
+ assert (downEvent.getActionMasked() == MotionEvent.ACTION_DOWN);
+ if (!mWindowManagerInternal.isPointInsideWindow(
+ focusedWindowToken, mCurrentDisplayId, downEvent.getRawX(), downEvent.getRawY())) {
+ Slog.e(TAG, "Cannot start handwriting session: "
+ + "Stylus gesture did not start inside the focused window.");
+ return null;
+ }
if (DEBUG) Slog.d(TAG, "Starting handwriting session in display: " + mCurrentDisplayId);
mInputManagerInternal.pilferPointers(mHandwritingSurface.getInputChannel().getToken());
@@ -226,13 +229,17 @@ final class HandwritingModeController {
}
if (!(ev instanceof MotionEvent)) {
- Slog.e("Stylus", "Received non-motion event in stylus monitor.");
+ Slog.wtf(TAG, "Received non-motion event in stylus monitor.");
return false;
}
final MotionEvent event = (MotionEvent) ev;
if (!isStylusEvent(event)) {
return false;
}
+ if (event.getDisplayId() != mCurrentDisplayId) {
+ Slog.wtf(TAG, "Received stylus event associated with the incorrect display.");
+ return false;
+ }
onStylusEvent(event);
return true;
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
index e62c5c13f04d..170331032086 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
@@ -30,6 +30,7 @@ import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputMethodSubtype;
+import android.window.ImeOnBackInvokedDispatcher;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodNavButtonFlags;
@@ -148,10 +149,11 @@ final class IInputMethodInvoker {
@AnyThread
void startInput(IBinder startInputToken, IInputContext inputContext, EditorInfo attribute,
- boolean restarting, @InputMethodNavButtonFlags int navButtonFlags) {
+ boolean restarting, @InputMethodNavButtonFlags int navButtonFlags,
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
try {
mTarget.startInput(startInputToken, inputContext, attribute, restarting,
- navButtonFlags);
+ navButtonFlags, imeDispatcher);
} catch (RemoteException e) {
logRemoteException(e);
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 6af00b3fbeea..ea2b1571c0ae 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -150,6 +150,7 @@ import android.view.inputmethod.InputMethodEditorTraceProto.InputMethodServiceTr
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
+import android.window.ImeOnBackInvokedDispatcher;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
@@ -616,6 +617,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
IInputContext mCurInputContext;
/**
+ * The {@link ImeOnBackInvokedDispatcher} last provided by the current client to
+ * receive {@link android.window.OnBackInvokedCallback}s forwarded from IME.
+ */
+ ImeOnBackInvokedDispatcher mCurImeDispatcher;
+
+ /**
* The {@link IRemoteAccessibilityInputConnection} last provided by the current client.
*/
@Nullable IRemoteAccessibilityInputConnection mCurRemoteAccessibilityInputConnection;
@@ -2623,7 +2630,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final SessionState session = mCurClient.curSession;
setEnabledSessionLocked(session);
session.method.startInput(startInputToken, mCurInputContext, mCurAttribute, restarting,
- navButtonFlags);
+ navButtonFlags, mCurImeDispatcher);
if (mShowRequested) {
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
showCurrentInputLocked(mCurFocusedWindow, getAppShowFlagsLocked(), null,
@@ -2733,7 +2740,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
@NonNull EditorInfo attribute, @StartInputFlags int startInputFlags,
@StartInputReason int startInputReason,
- int unverifiedTargetSdkVersion) {
+ int unverifiedTargetSdkVersion,
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
// If no method is currently selected, do nothing.
final String selectedMethodId = getSelectedMethodIdLocked();
if (selectedMethodId == null) {
@@ -2777,6 +2785,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mCurClient = cs;
mCurInputContext = inputContext;
mCurRemoteAccessibilityInputConnection = remoteAccessibilityInputConnection;
+ mCurImeDispatcher = imeDispatcher;
mCurVirtualDisplayToScreenMatrix =
getVirtualDisplayToScreenMatrixLocked(cs.selfReportedDisplayId,
mDisplayIdToShowIme);
@@ -3780,10 +3789,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
- int unverifiedTargetSdkVersion) {
+ int unverifiedTargetSdkVersion,
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
return startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
startInputFlags, softInputMode, windowFlags, attribute, inputContext,
- remoteAccessibilityInputConnection, unverifiedTargetSdkVersion);
+ remoteAccessibilityInputConnection, unverifiedTargetSdkVersion,
+ imeDispatcher);
}
@NonNull
@@ -3792,7 +3803,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
int windowFlags, @Nullable EditorInfo attribute, @Nullable IInputContext inputContext,
@Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
- int unverifiedTargetSdkVersion) {
+ int unverifiedTargetSdkVersion,
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
if (windowToken == null) {
Slog.e(TAG, "windowToken cannot be null.");
return InputBindResult.NULL;
@@ -3829,7 +3841,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
client, windowToken, startInputFlags, softInputMode, windowFlags,
attribute, inputContext, remoteAccessibilityInputConnection,
- unverifiedTargetSdkVersion, userId);
+ unverifiedTargetSdkVersion, userId, imeDispatcher);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -3857,7 +3869,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
IInputContext inputContext,
@Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
- int unverifiedTargetSdkVersion, @UserIdInt int userId) {
+ int unverifiedTargetSdkVersion, @UserIdInt int userId,
+ @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
if (DEBUG) {
Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
+ InputMethodDebug.startInputReasonToString(startInputReason)
@@ -3868,7 +3881,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
+ InputMethodDebug.startInputFlagsToString(startInputFlags)
+ " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
+ " windowFlags=#" + Integer.toHexString(windowFlags)
- + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
+ + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion
+ + " imeDispatcher=" + imeDispatcher);
}
final ClientState cs = mClients.get(client.asBinder());
@@ -3952,7 +3966,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
if (attribute != null) {
return startInputUncheckedLocked(cs, inputContext,
remoteAccessibilityInputConnection, attribute, startInputFlags,
- startInputReason, unverifiedTargetSdkVersion);
+ startInputReason, unverifiedTargetSdkVersion, imeDispatcher);
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
@@ -3993,7 +4007,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
if (isTextEditor && attribute != null
&& shouldRestoreImeVisibility(windowToken, softInputMode)) {
res = startInputUncheckedLocked(cs, inputContext, remoteAccessibilityInputConnection,
- attribute, startInputFlags, startInputReason, unverifiedTargetSdkVersion);
+ attribute, startInputFlags, startInputReason, unverifiedTargetSdkVersion,
+ imeDispatcher);
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
return res;
@@ -4033,7 +4048,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext,
remoteAccessibilityInputConnection, attribute, startInputFlags,
- startInputReason, unverifiedTargetSdkVersion);
+ startInputReason, unverifiedTargetSdkVersion,
+ imeDispatcher);
didStart = true;
}
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -4065,7 +4081,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext,
remoteAccessibilityInputConnection, attribute, startInputFlags,
- startInputReason, unverifiedTargetSdkVersion);
+ startInputReason, unverifiedTargetSdkVersion,
+ imeDispatcher);
didStart = true;
}
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -4085,7 +4102,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext,
remoteAccessibilityInputConnection, attribute, startInputFlags,
- startInputReason, unverifiedTargetSdkVersion);
+ startInputReason, unverifiedTargetSdkVersion,
+ imeDispatcher);
didStart = true;
}
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -4115,7 +4133,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
res = startInputUncheckedLocked(cs, inputContext,
remoteAccessibilityInputConnection, attribute, startInputFlags,
- startInputReason, unverifiedTargetSdkVersion);
+ startInputReason, unverifiedTargetSdkVersion,
+ imeDispatcher);
} else {
res = InputBindResult.NULL_EDITOR_INFO;
}
@@ -5099,9 +5118,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
case MSG_RESET_HANDWRITING: {
synchronized (ImfLock.class) {
if (mBindingController.supportsStylusHandwriting()
- && getCurMethodLocked() != null && mCurFocusedWindow != null) {
- mHwController.initializeHandwritingSpy(
- mCurTokenDisplayId, mCurFocusedWindow);
+ && getCurMethodLocked() != null) {
+ mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
} else {
mHwController.reset();
}
@@ -5111,14 +5129,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
case MSG_START_HANDWRITING:
synchronized (ImfLock.class) {
IInputMethodInvoker curMethod = getCurMethodLocked();
- if (curMethod == null) {
+ if (curMethod == null || mCurFocusedWindow == null) {
return true;
}
final HandwritingModeController.HandwritingSession session =
mHwController.startHandwritingSession(
msg.arg1 /*requestId*/,
msg.arg2 /*pid*/,
- mBindingController.getCurMethodUid());
+ mBindingController.getCurMethodUid(),
+ mCurFocusedWindow);
if (session == null) {
Slog.e(TAG,
"Failed to start handwriting session for requestId: " + msg.arg1);
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 92703ec86d06..604e8f3949f4 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -60,8 +60,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.NoSuchElementException;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* This is the system implementation of a Session. Apps will interact with the
@@ -1159,6 +1159,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void sendCommand(String packageName, int pid, int uid, String command, Bundle args,
ResultReceiver cb) {
try {
+ final String reason = TAG + ":" + command;
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onCommand(packageName, pid, uid, command, args, cb);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in sendCommand.", e);
@@ -1168,6 +1171,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void sendCustomAction(String packageName, int pid, int uid, String action,
Bundle args) {
try {
+ final String reason = TAG + ":custom-" + action;
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onCustomAction(packageName, pid, uid, action, args);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in sendCustomAction.", e);
@@ -1176,6 +1182,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void prepare(String packageName, int pid, int uid) {
try {
+ final String reason = TAG + ":prepare";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onPrepare(packageName, pid, uid);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in prepare.", e);
@@ -1185,6 +1194,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void prepareFromMediaId(String packageName, int pid, int uid, String mediaId,
Bundle extras) {
try {
+ final String reason = TAG + ":prepareFromMediaId";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onPrepareFromMediaId(packageName, pid, uid, mediaId, extras);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in prepareFromMediaId.", e);
@@ -1194,6 +1206,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void prepareFromSearch(String packageName, int pid, int uid, String query,
Bundle extras) {
try {
+ final String reason = TAG + ":prepareFromSearch";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onPrepareFromSearch(packageName, pid, uid, query, extras);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in prepareFromSearch.", e);
@@ -1202,6 +1217,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void prepareFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
try {
+ final String reason = TAG + ":prepareFromUri";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onPrepareFromUri(packageName, pid, uid, uri, extras);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in prepareFromUri.", e);
@@ -1210,6 +1228,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void play(String packageName, int pid, int uid) {
try {
+ final String reason = TAG + ":play";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onPlay(packageName, pid, uid);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in play.", e);
@@ -1219,6 +1240,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void playFromMediaId(String packageName, int pid, int uid, String mediaId,
Bundle extras) {
try {
+ final String reason = TAG + ":playFromMediaId";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onPlayFromMediaId(packageName, pid, uid, mediaId, extras);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in playFromMediaId.", e);
@@ -1228,6 +1252,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void playFromSearch(String packageName, int pid, int uid, String query,
Bundle extras) {
try {
+ final String reason = TAG + ":playFromSearch";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onPlayFromSearch(packageName, pid, uid, query, extras);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in playFromSearch.", e);
@@ -1236,6 +1263,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void playFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
try {
+ final String reason = TAG + ":playFromUri";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onPlayFromUri(packageName, pid, uid, uri, extras);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in playFromUri.", e);
@@ -1244,6 +1274,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void skipToTrack(String packageName, int pid, int uid, long id) {
try {
+ final String reason = TAG + ":skipToTrack";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onSkipToTrack(packageName, pid, uid, id);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in skipToTrack", e);
@@ -1252,6 +1285,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void pause(String packageName, int pid, int uid) {
try {
+ final String reason = TAG + ":pause";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onPause(packageName, pid, uid);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in pause.", e);
@@ -1260,6 +1296,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void stop(String packageName, int pid, int uid) {
try {
+ final String reason = TAG + ":stop";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onStop(packageName, pid, uid);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in stop.", e);
@@ -1268,6 +1307,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void next(String packageName, int pid, int uid) {
try {
+ final String reason = TAG + ":next";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onNext(packageName, pid, uid);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in next.", e);
@@ -1276,6 +1318,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void previous(String packageName, int pid, int uid) {
try {
+ final String reason = TAG + ":previous";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onPrevious(packageName, pid, uid);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in previous.", e);
@@ -1284,6 +1329,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void fastForward(String packageName, int pid, int uid) {
try {
+ final String reason = TAG + ":fastForward";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onFastForward(packageName, pid, uid);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in fastForward.", e);
@@ -1292,6 +1340,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void rewind(String packageName, int pid, int uid) {
try {
+ final String reason = TAG + ":rewind";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onRewind(packageName, pid, uid);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in rewind.", e);
@@ -1300,6 +1351,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void seekTo(String packageName, int pid, int uid, long pos) {
try {
+ final String reason = TAG + ":seekTo";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onSeekTo(packageName, pid, uid, pos);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in seekTo.", e);
@@ -1308,6 +1362,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void rate(String packageName, int pid, int uid, Rating rating) {
try {
+ final String reason = TAG + ":rate";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onRate(packageName, pid, uid, rating);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in rate.", e);
@@ -1316,6 +1373,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void setPlaybackSpeed(String packageName, int pid, int uid, float speed) {
try {
+ final String reason = TAG + ":setPlaybackSpeed";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onSetPlaybackSpeed(packageName, pid, uid, speed);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in setPlaybackSpeed.", e);
@@ -1325,6 +1385,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
int direction) {
try {
+ final String reason = TAG + ":adjustVolume";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
if (asSystemService) {
mCb.onAdjustVolume(mContext.getPackageName(), Process.myPid(),
Process.SYSTEM_UID, direction);
@@ -1338,6 +1401,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void setVolumeTo(String packageName, int pid, int uid, int value) {
try {
+ final String reason = TAG + ":setVolumeTo";
+ mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
+ pid, uid, packageName, reason);
mCb.onSetVolumeTo(packageName, pid, uid, value);
} catch (RemoteException e) {
Log.e(TAG, "Remote failure in setVolumeTo.", e);
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index 2824585bf5aa..39119948fa3e 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -34,13 +34,14 @@ import android.content.Context;
import android.content.pm.ApkChecksum;
import android.content.pm.Checksum;
import android.content.pm.IOnChecksumsReadyListener;
-import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.content.pm.SigningDetails.SignatureSchemeVersion;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
+import android.os.Environment;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -63,7 +64,6 @@ import android.util.apk.VerityBuilder;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.security.VerityUtils;
-import com.android.server.LocalServices;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.ByteArrayOutputStream;
@@ -637,9 +637,18 @@ public class ApkChecksums {
return null;
}
+ private static boolean containsFile(File dir, String filePath) {
+ if (dir == null) {
+ return false;
+ }
+ return FileUtils.contains(dir.getAbsolutePath(), filePath);
+ }
+
private static ApkChecksum extractHashFromFS(String split, String filePath) {
// verity first
- {
+ // Skip /product folder.
+ // TODO(b/231354111): remove this hack once we are allowed to change SELinux rules.
+ if (!containsFile(Environment.getProductDirectory(), filePath)) {
byte[] hash = VerityUtils.getFsverityRootHash(filePath);
if (hash != null) {
return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, hash);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 320b06f6dc3e..32f0f109821d 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -119,7 +119,7 @@ public class Installer extends SystemService {
IInstalld.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
private final boolean mIsolated;
-
+ private volatile boolean mDeferSetFirstBoot;
private volatile IInstalld mInstalld;
private volatile Object mWarnIfHeld;
@@ -171,6 +171,7 @@ public class Installer extends SystemService {
mInstalld = IInstalld.Stub.asInterface(binder);
try {
invalidateMounts();
+ executeDeferredActions();
} catch (InstallerException ignored) {
}
} else {
@@ -180,6 +181,15 @@ public class Installer extends SystemService {
}
/**
+ * Perform any deferred actions on mInstalld while the connection could not be made.
+ */
+ private void executeDeferredActions() throws InstallerException {
+ if (mDeferSetFirstBoot) {
+ setFirstBoot();
+ }
+ }
+
+ /**
* Do several pre-flight checks before making a remote call.
*
* @return if the remote call should continue.
@@ -291,8 +301,15 @@ public class Installer extends SystemService {
return;
}
try {
- mInstalld.setFirstBoot();
- } catch (RemoteException e) {
+ // mInstalld might be null if the connection could not be established.
+ if (mInstalld != null) {
+ mInstalld.setFirstBoot();
+ } else {
+ // if it is null while trying to set the first boot, set a flag to try and set the
+ // first boot when the connection is eventually established
+ mDeferSetFirstBoot = true;
+ }
+ } catch (Exception e) {
throw InstallerException.from(e);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 4df54b74bb1d..fa0c6c393cdc 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -166,18 +166,19 @@ class ShortcutPackage extends ShortcutPackageItem {
* An in-memory copy of shortcuts for this package that was loaded from xml, keyed on IDs.
*/
@GuardedBy("mLock")
- final ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>();
+ private final ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>();
/**
* A temporary copy of shortcuts that are to be cleared once persisted into AppSearch, keyed on
* IDs.
*/
@GuardedBy("mLock")
- private ArrayMap<String, ShortcutInfo> mTransientShortcuts = new ArrayMap<>(0);
+ private final ArrayMap<String, ShortcutInfo> mTransientShortcuts = new ArrayMap<>(0);
/**
* All the share targets from the package
*/
+ @GuardedBy("mLock")
private final ArrayList<ShareTargetInfo> mShareTargets = new ArrayList<>(0);
/**
@@ -231,7 +232,9 @@ class ShortcutPackage extends ShortcutPackageItem {
}
public int getShortcutCount() {
- return mShortcuts.size();
+ synchronized (mLock) {
+ return mShortcuts.size();
+ }
}
@Override
@@ -272,7 +275,9 @@ class ShortcutPackage extends ShortcutPackageItem {
@Nullable
public ShortcutInfo findShortcutById(@Nullable final String id) {
if (id == null) return null;
- return mShortcuts.get(id);
+ synchronized (mLock) {
+ return mShortcuts.get(id);
+ }
}
public boolean isShortcutExistsAndInvisibleToPublisher(String id) {
@@ -347,11 +352,14 @@ class ShortcutPackage extends ShortcutPackageItem {
* Delete a shortcut by ID. This will *always* remove it even if it's immutable or invisible.
*/
private ShortcutInfo forceDeleteShortcutInner(@NonNull String id) {
- final ShortcutInfo shortcut = mShortcuts.remove(id);
- if (shortcut != null) {
- removeIcon(shortcut);
- shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
- | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED_ALL);
+ final ShortcutInfo shortcut;
+ synchronized (mLock) {
+ shortcut = mShortcuts.remove(id);
+ if (shortcut != null) {
+ removeIcon(shortcut);
+ shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
+ | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED_ALL);
+ }
}
return shortcut;
}
@@ -524,14 +532,16 @@ class ShortcutPackage extends ShortcutPackageItem {
public List<ShortcutInfo> deleteAllDynamicShortcuts() {
final long now = mShortcutUser.mService.injectCurrentTimeMillis();
boolean changed = false;
- for (int i = mShortcuts.size() - 1; i >= 0; i--) {
- ShortcutInfo si = mShortcuts.valueAt(i);
- if (si.isDynamic() && si.isVisibleToPublisher()) {
- changed = true;
-
- si.setTimestamp(now);
- si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
- si.setRank(0); // It may still be pinned, so clear the rank.
+ synchronized (mLock) {
+ for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+ ShortcutInfo si = mShortcuts.valueAt(i);
+ if (si.isDynamic() && si.isVisibleToPublisher()) {
+ changed = true;
+
+ si.setTimestamp(now);
+ si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+ si.setRank(0); // It may still be pinned, so clear the rank.
+ }
}
}
removeAllShortcutsAsync();
@@ -874,59 +884,63 @@ class ShortcutPackage extends ShortcutPackageItem {
*/
public List<ShortcutManager.ShareShortcutInfo> getMatchingShareTargets(
@NonNull IntentFilter filter) {
- final List<ShareTargetInfo> matchedTargets = new ArrayList<>();
- for (int i = 0; i < mShareTargets.size(); i++) {
- final ShareTargetInfo target = mShareTargets.get(i);
- for (ShareTargetInfo.TargetData data : target.mTargetData) {
- if (filter.hasDataType(data.mMimeType)) {
- // Matched at least with one data type
- matchedTargets.add(target);
- break;
+ synchronized (mLock) {
+ final List<ShareTargetInfo> matchedTargets = new ArrayList<>();
+ for (int i = 0; i < mShareTargets.size(); i++) {
+ final ShareTargetInfo target = mShareTargets.get(i);
+ for (ShareTargetInfo.TargetData data : target.mTargetData) {
+ if (filter.hasDataType(data.mMimeType)) {
+ // Matched at least with one data type
+ matchedTargets.add(target);
+ break;
+ }
}
}
- }
- if (matchedTargets.isEmpty()) {
- return new ArrayList<>();
- }
+ if (matchedTargets.isEmpty()) {
+ return new ArrayList<>();
+ }
- // Get the list of all dynamic shortcuts in this package.
- final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
- // Pass callingLauncher to ensure pinned flag marked by system ui, e.g. ShareSheet, are
- // included in the result
- findAll(shortcuts, ShortcutInfo::isNonManifestVisible,
- ShortcutInfo.CLONE_REMOVE_FOR_APP_PREDICTION,
- mShortcutUser.mService.mContext.getPackageName(),
- 0, /*getPinnedByAnyLauncher=*/ false);
+ // Get the list of all dynamic shortcuts in this package.
+ final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
+ // Pass callingLauncher to ensure pinned flag marked by system ui, e.g. ShareSheet, are
+ // included in the result
+ findAll(shortcuts, ShortcutInfo::isNonManifestVisible,
+ ShortcutInfo.CLONE_REMOVE_FOR_APP_PREDICTION,
+ mShortcutUser.mService.mContext.getPackageName(),
+ 0, /*getPinnedByAnyLauncher=*/ false);
- final List<ShortcutManager.ShareShortcutInfo> result = new ArrayList<>();
- for (int i = 0; i < shortcuts.size(); i++) {
- final Set<String> categories = shortcuts.get(i).getCategories();
- if (categories == null || categories.isEmpty()) {
- continue;
- }
- for (int j = 0; j < matchedTargets.size(); j++) {
- // Shortcut must have all of share target categories
- boolean hasAllCategories = true;
- final ShareTargetInfo target = matchedTargets.get(j);
- for (int q = 0; q < target.mCategories.length; q++) {
- if (!categories.contains(target.mCategories[q])) {
- hasAllCategories = false;
+ final List<ShortcutManager.ShareShortcutInfo> result = new ArrayList<>();
+ for (int i = 0; i < shortcuts.size(); i++) {
+ final Set<String> categories = shortcuts.get(i).getCategories();
+ if (categories == null || categories.isEmpty()) {
+ continue;
+ }
+ for (int j = 0; j < matchedTargets.size(); j++) {
+ // Shortcut must have all of share target categories
+ boolean hasAllCategories = true;
+ final ShareTargetInfo target = matchedTargets.get(j);
+ for (int q = 0; q < target.mCategories.length; q++) {
+ if (!categories.contains(target.mCategories[q])) {
+ hasAllCategories = false;
+ break;
+ }
+ }
+ if (hasAllCategories) {
+ result.add(new ShortcutManager.ShareShortcutInfo(shortcuts.get(i),
+ new ComponentName(getPackageName(), target.mTargetClass)));
break;
}
}
- if (hasAllCategories) {
- result.add(new ShortcutManager.ShareShortcutInfo(shortcuts.get(i),
- new ComponentName(getPackageName(), target.mTargetClass)));
- break;
- }
}
+ return result;
}
- return result;
}
public boolean hasShareTargets() {
- return !mShareTargets.isEmpty();
+ synchronized (mLock) {
+ return !mShareTargets.isEmpty();
+ }
}
/**
@@ -935,38 +949,40 @@ class ShortcutPackage extends ShortcutPackageItem {
* the app's Xml resource.
*/
int getSharingShortcutCount() {
- if (mShareTargets.isEmpty()) {
- return 0;
- }
+ synchronized (mLock) {
+ if (mShareTargets.isEmpty()) {
+ return 0;
+ }
- // Get the list of all dynamic shortcuts in this package
- final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
- findAll(shortcuts, ShortcutInfo::isNonManifestVisible,
- ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+ // Get the list of all dynamic shortcuts in this package
+ final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
+ findAll(shortcuts, ShortcutInfo::isNonManifestVisible,
+ ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
- int sharingShortcutCount = 0;
- for (int i = 0; i < shortcuts.size(); i++) {
- final Set<String> categories = shortcuts.get(i).getCategories();
- if (categories == null || categories.isEmpty()) {
- continue;
- }
- for (int j = 0; j < mShareTargets.size(); j++) {
- // A SharingShortcut must have all of share target categories
- boolean hasAllCategories = true;
- final ShareTargetInfo target = mShareTargets.get(j);
- for (int q = 0; q < target.mCategories.length; q++) {
- if (!categories.contains(target.mCategories[q])) {
- hasAllCategories = false;
+ int sharingShortcutCount = 0;
+ for (int i = 0; i < shortcuts.size(); i++) {
+ final Set<String> categories = shortcuts.get(i).getCategories();
+ if (categories == null || categories.isEmpty()) {
+ continue;
+ }
+ for (int j = 0; j < mShareTargets.size(); j++) {
+ // A SharingShortcut must have all of share target categories
+ boolean hasAllCategories = true;
+ final ShareTargetInfo target = mShareTargets.get(j);
+ for (int q = 0; q < target.mCategories.length; q++) {
+ if (!categories.contains(target.mCategories[q])) {
+ hasAllCategories = false;
+ break;
+ }
+ }
+ if (hasAllCategories) {
+ sharingShortcutCount++;
break;
}
}
- if (hasAllCategories) {
- sharingShortcutCount++;
- break;
- }
}
+ return sharingShortcutCount;
}
- return sharingShortcutCount;
}
/**
@@ -1090,19 +1106,25 @@ class ShortcutPackage extends ShortcutPackageItem {
// Now prepare to publish manifest shortcuts.
List<ShortcutInfo> newManifestShortcutList = null;
- try {
- newManifestShortcutList = ShortcutParser.parseShortcuts(mShortcutUser.mService,
- getPackageName(), getPackageUserId(), mShareTargets);
- } catch (IOException|XmlPullParserException e) {
- Slog.e(TAG, "Failed to load shortcuts from AndroidManifest.xml.", e);
+ final int shareTargetSize;
+ synchronized (mLock) {
+ try {
+ shareTargetSize = mShareTargets.size();
+ newManifestShortcutList = ShortcutParser.parseShortcuts(mShortcutUser.mService,
+ getPackageName(), getPackageUserId(), mShareTargets);
+ } catch (IOException | XmlPullParserException e) {
+ Slog.e(TAG, "Failed to load shortcuts from AndroidManifest.xml.", e);
+ }
}
final int manifestShortcutSize = newManifestShortcutList == null ? 0
: newManifestShortcutList.size();
if (ShortcutService.DEBUG || ShortcutService.DEBUG_REBOOT) {
Slog.d(TAG,
- String.format("Package %s has %d manifest shortcut(s), and %d share target(s)",
- getPackageName(), manifestShortcutSize, mShareTargets.size()));
+ String.format(
+ "Package %s has %d manifest shortcut(s), and %d share target(s)",
+ getPackageName(), manifestShortcutSize, shareTargetSize));
}
+
if (isNewApp && (manifestShortcutSize == 0)) {
// If it's a new app, and it doesn't have manifest shortcuts, then nothing to do.
@@ -1701,37 +1723,38 @@ class ShortcutPackage extends ShortcutPackageItem {
@Override
public void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
throws IOException, XmlPullParserException {
- final int size = mShortcuts.size();
- final int shareTargetSize = mShareTargets.size();
+ synchronized (mLock) {
+ final int size = mShortcuts.size();
+ final int shareTargetSize = mShareTargets.size();
- if (hasNoShortcut() && shareTargetSize == 0 && mApiCallCount == 0) {
- return; // nothing to write.
- }
+ if (hasNoShortcut() && shareTargetSize == 0 && mApiCallCount == 0) {
+ return; // nothing to write.
+ }
- out.startTag(null, TAG_ROOT);
+ out.startTag(null, TAG_ROOT);
- ShortcutService.writeAttr(out, ATTR_NAME, getPackageName());
- ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
- ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
- if (!forBackup) {
- synchronized (mLock) {
- ShortcutService.writeAttr(out, ATTR_SCHEMA_VERSON, (mIsAppSearchSchemaUpToDate)
+ ShortcutService.writeAttr(out, ATTR_NAME, getPackageName());
+ ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
+ ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
+ if (!forBackup) {
+ ShortcutService.writeAttr(out, ATTR_SCHEMA_VERSON, mIsAppSearchSchemaUpToDate
? AppSearchShortcutInfo.SCHEMA_VERSION : 0);
}
- }
- getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup);
+ getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup);
- for (int j = 0; j < size; j++) {
- saveShortcut(out, mShortcuts.valueAt(j), forBackup, getPackageInfo().isBackupAllowed());
- }
+ for (int j = 0; j < size; j++) {
+ saveShortcut(
+ out, mShortcuts.valueAt(j), forBackup, getPackageInfo().isBackupAllowed());
+ }
- if (!forBackup) {
- for (int j = 0; j < shareTargetSize; j++) {
- mShareTargets.get(j).saveToXml(out);
+ if (!forBackup) {
+ for (int j = 0; j < shareTargetSize; j++) {
+ mShareTargets.get(j).saveToXml(out);
+ }
}
- }
- out.endTag(null, TAG_ROOT);
+ out.endTag(null, TAG_ROOT);
+ }
}
private void saveShortcut(TypedXmlSerializer out, ShortcutInfo si, boolean forBackup,
@@ -1917,38 +1940,38 @@ class ShortcutPackage extends ShortcutPackageItem {
synchronized (ret.mLock) {
ret.mIsAppSearchSchemaUpToDate = ShortcutService.parseIntAttribute(
parser, ATTR_SCHEMA_VERSON, 0) == AppSearchShortcutInfo.SCHEMA_VERSION;
- }
- ret.mApiCallCount = ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
- ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
-
- final int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
- final int depth = parser.getDepth();
- final String tag = parser.getName();
- if (depth == outerDepth + 1) {
- switch (tag) {
- case ShortcutPackageInfo.TAG_ROOT:
- ret.getPackageInfo().loadFromXml(parser, fromBackup);
+ ret.mApiCallCount = ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
+ ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
- continue;
- case TAG_SHORTCUT:
- final ShortcutInfo si = parseShortcut(parser, packageName,
- shortcutUser.getUserId(), fromBackup);
- // Don't use addShortcut(), we don't need to save the icon.
- ret.mShortcuts.put(si.getId(), si);
- continue;
- case TAG_SHARE_TARGET:
- ret.mShareTargets.add(ShareTargetInfo.loadFromXml(parser));
- continue;
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
}
+ final int depth = parser.getDepth();
+ final String tag = parser.getName();
+ if (depth == outerDepth + 1) {
+ switch (tag) {
+ case ShortcutPackageInfo.TAG_ROOT:
+ ret.getPackageInfo().loadFromXml(parser, fromBackup);
+
+ continue;
+ case TAG_SHORTCUT:
+ final ShortcutInfo si = parseShortcut(parser, packageName,
+ shortcutUser.getUserId(), fromBackup);
+ // Don't use addShortcut(), we don't need to save the icon.
+ ret.mShortcuts.put(si.getId(), si);
+ continue;
+ case TAG_SHARE_TARGET:
+ ret.mShareTargets.add(ShareTargetInfo.loadFromXml(parser));
+ continue;
+ }
+ }
+ ShortcutService.warnForInvalidTag(depth, tag);
}
- ShortcutService.warnForInvalidTag(depth, tag);
}
return ret;
}
@@ -2152,7 +2175,9 @@ class ShortcutPackage extends ShortcutPackageItem {
@VisibleForTesting
List<ShareTargetInfo> getAllShareTargetsForTest() {
- return new ArrayList<>(mShareTargets);
+ synchronized (mLock) {
+ return new ArrayList<>(mShareTargets);
+ }
}
@Override
@@ -2291,15 +2316,19 @@ class ShortcutPackage extends ShortcutPackageItem {
private void saveShortcut(@NonNull final Collection<ShortcutInfo> shortcuts) {
Objects.requireNonNull(shortcuts);
- for (ShortcutInfo si : shortcuts) {
- mShortcuts.put(si.getId(), si);
+ synchronized (mLock) {
+ for (ShortcutInfo si : shortcuts) {
+ mShortcuts.put(si.getId(), si);
+ }
}
}
@Nullable
List<ShortcutInfo> findAll(@NonNull final Collection<String> ids) {
- return ids.stream().map(mShortcuts::get)
- .filter(Objects::nonNull).collect(Collectors.toList());
+ synchronized (mLock) {
+ return ids.stream().map(mShortcuts::get)
+ .filter(Objects::nonNull).collect(Collectors.toList());
+ }
}
private void forEachShortcut(@NonNull final Consumer<ShortcutInfo> cb) {
@@ -2318,10 +2347,12 @@ class ShortcutPackage extends ShortcutPackageItem {
private void forEachShortcutStopWhen(
@NonNull final Function<ShortcutInfo, Boolean> cb) {
- for (int i = mShortcuts.size() - 1; i >= 0; i--) {
- final ShortcutInfo si = mShortcuts.valueAt(i);
- if (cb.apply(si)) {
- return;
+ synchronized (mLock) {
+ for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+ final ShortcutInfo si = mShortcuts.valueAt(i);
+ if (cb.apply(si)) {
+ return;
+ }
}
}
}
@@ -2461,6 +2492,7 @@ class ShortcutPackage extends ShortcutPackageItem {
})));
}
+ @GuardedBy("mLock")
@Override
void scheduleSaveToAppSearchLocked() {
final Map<String, ShortcutInfo> copy = new ArrayMap<>(mShortcuts);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b14214189833..d8e7fbe8b296 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -27,7 +27,6 @@ import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.O;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
@@ -130,7 +129,6 @@ import android.media.AudioManagerInternal;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.session.MediaSessionLegacyHelper;
-import android.os.BatteryManagerInternal;
import android.os.Binder;
import android.os.Bundle;
import android.os.DeviceIdleManager;
@@ -396,7 +394,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
PowerManagerInternal mPowerManagerInternal;
IStatusBarService mStatusBarService;
StatusBarManagerInternal mStatusBarManagerInternal;
- BatteryManagerInternal mBatteryManagerInternal;
AudioManagerInternal mAudioManagerInternal;
DisplayManager mDisplayManager;
DisplayManagerInternal mDisplayManagerInternal;
@@ -791,8 +788,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void onWakeUp() {
synchronized (mLock) {
- if (shouldEnableWakeGestureLp()
- && getBatteryManagerInternal().getPlugType() != BATTERY_PLUGGED_WIRELESS) {
+ if (shouldEnableWakeGestureLp()) {
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
"Wake Up");
wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
@@ -849,15 +845,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- BatteryManagerInternal getBatteryManagerInternal() {
- synchronized (mServiceAcquireLock) {
- if (mBatteryManagerInternal == null) {
- mBatteryManagerInternal =
- LocalServices.getService(BatteryManagerInternal.class);
- }
- return mBatteryManagerInternal;
- }
- }
// returns true if the key was handled and should not be passed to the user
private boolean backKeyPress() {
diff --git a/services/core/java/com/android/server/utils/WatchedArrayList.java b/services/core/java/com/android/server/utils/WatchedArrayList.java
index 6059f9675e34..75e39ebb32d8 100644
--- a/services/core/java/com/android/server/utils/WatchedArrayList.java
+++ b/services/core/java/com/android/server/utils/WatchedArrayList.java
@@ -416,7 +416,7 @@ public class WatchedArrayList<E> extends WatchableImpl
dst.mStorage.ensureCapacity(end);
for (int i = 0; i < end; i++) {
final E val = Snapshots.maybeSnapshot(src.get(i));
- dst.add(i, val);
+ dst.add(val);
}
dst.seal();
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 63619e543a6d..f1dbad61a76d 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -446,6 +446,43 @@ final class AccessibilityController {
// Not relevant for the window observer.
}
+ public Pair<Matrix, MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
+ IBinder token) {
+ synchronized (mService.mGlobalLock) {
+ final Matrix transformationMatrix = new Matrix();
+ final MagnificationSpec magnificationSpec = new MagnificationSpec();
+
+ final WindowState windowState = mService.mWindowMap.get(token);
+ if (windowState != null) {
+ windowState.getTransformationMatrix(new float[9], transformationMatrix);
+
+ if (hasCallbacks()) {
+ final MagnificationSpec otherMagnificationSpec =
+ getMagnificationSpecForWindow(windowState);
+ if (otherMagnificationSpec != null && !otherMagnificationSpec.isNop()) {
+ magnificationSpec.setTo(otherMagnificationSpec);
+ }
+ }
+ }
+
+ return new Pair<>(transformationMatrix, magnificationSpec);
+ }
+ }
+
+ MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
+ if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+ mAccessibilityTracing.logTrace(TAG + ".getMagnificationSpecForWindow",
+ FLAGS_MAGNIFICATION_CALLBACK,
+ "windowState={" + windowState + "}");
+ }
+ final int displayId = windowState.getDisplayId();
+ final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+ if (displayMagnifier != null) {
+ return displayMagnifier.getMagnificationSpecForWindow(windowState);
+ }
+ return null;
+ }
+
boolean hasCallbacks() {
if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
| FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index cb6559715c55..701fc9441acb 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -68,7 +68,6 @@ import static com.android.server.wm.AppTransition.isNormalTransit;
import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldAttachNavBarToApp;
import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldStartNonAppWindowAnimationsForKeyguardExit;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WallpaperAnimationAdapter.shouldStartWallpaperAnimation;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -1143,17 +1142,13 @@ public class AppTransitionController {
if (activity == null) {
continue;
}
- if (activity.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) {
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "Delaying app transition for recents animation to finish");
- return false;
- }
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Check opening app=%s: allDrawn=%b startingDisplayed=%b "
+ "startingMoved=%b isRelaunching()=%b startingWindow=%s",
activity, activity.allDrawn, activity.startingDisplayed,
activity.startingMoved, activity.isRelaunching(),
activity.mStartingWindow);
+
final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) {
return false;
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index ee7d9a9b3f2d..46ce43335f01 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -153,10 +153,10 @@ class BLASTSyncEngine {
for (WindowContainer wc : mRootMembers) {
wc.waitForSyncTransactionCommit(wcAwaitingCommit);
}
- final Runnable callback = new Runnable() {
+ class CommitCallback implements Runnable {
// Can run a second time if the action completes after the timeout.
boolean ran = false;
- public void run() {
+ public void onCommitted() {
synchronized (mWm.mGlobalLock) {
if (ran) {
return;
@@ -171,8 +171,23 @@ class BLASTSyncEngine {
wcAwaitingCommit.clear();
}
}
+
+ // Called in timeout
+ @Override
+ public void run() {
+ // Sometimes we get a trace, sometimes we get a bugreport without
+ // a trace. Since these kind of ANRs can trigger such an issue,
+ // try and ensure we will have some visibility in both cases.
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionCommitTimeout");
+ Slog.e(TAG, "WM sent Transaction to organized, but never received" +
+ " commit callback. Application ANR likely to follow.");
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ onCommitted();
+
+ }
};
- merged.addTransactionCommittedListener((r) -> { r.run(); }, callback::run);
+ CommitCallback callback = new CommitCallback();
+ merged.addTransactionCommittedListener((r) -> { r.run(); }, callback::onCommitted);
mWm.mH.postDelayed(callback, BLAST_TIMEOUT_DURATION);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady");
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index aaae82d07976..247117e707c8 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -187,7 +187,6 @@ class BackNavigationController {
if (backType == BackNavigationInfo.TYPE_CALLBACK
|| currentActivity == null
|| currentTask == null
- || currentTask.getDisplayContent().getImeContainer().isVisible()
|| currentActivity.isActivityTypeHome()) {
return infoBuilder
.setType(backType)
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index a480c37fbcf3..2f00bc821678 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1584,14 +1584,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return true;
}
- void forAllWindowContainers(Consumer<WindowContainer> callback) {
- callback.accept(this);
- final int count = mChildren.size();
- for (int i = 0; i < count; i++) {
- mChildren.get(i).forAllWindowContainers(callback);
- }
- }
-
/**
* For all windows at or below this container call the callback.
* @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index f8bc26a7d91d..c0d7d1362ac3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -23,17 +23,18 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ClipData;
import android.content.Context;
+import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerInternal;
import android.os.Bundle;
import android.os.IBinder;
+import android.util.Pair;
import android.view.Display;
import android.view.IInputFilter;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IWindow;
import android.view.InputChannel;
-import android.view.InputWindowHandle;
import android.view.MagnificationSpec;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -459,6 +460,17 @@ public abstract class WindowManagerInternal {
public abstract void getWindowFrame(IBinder token, Rect outBounds);
/**
+ * Get the transformation matrix and MagnificationSpec given its token.
+ *
+ * @param token The token.
+ * @return The pair of the transformation matrix and magnification spec.
+ */
+ // TODO (b/231663133): Long term solution for tracking window when the
+ // FLAG_RETRIEVE_INTERACTIVE_WINDOWS is unset.
+ public abstract Pair<Matrix, MagnificationSpec>
+ getWindowTransformationMatrixAndMagnificationSpec(IBinder token);
+
+ /**
* Opens the global actions dialog.
*/
public abstract void showGlobalActions();
@@ -849,24 +861,12 @@ public abstract class WindowManagerInternal {
public abstract SurfaceControl getHandwritingSurfaceForDisplay(int displayId);
/**
- * Replaces the touchable region of the provided input surface with the crop of the window with
- * the provided token. This method will associate the inputSurface with a copy of
- * the given inputWindowHandle, where the copy is configured using
- * {@link InputWindowHandle#replaceTouchableRegionWithCrop(SurfaceControl)} with the surface
- * of the provided windowToken.
- *
- * This is a no-op if windowToken is not valid or the window is not found.
- *
- * This does not change any other properties of the inputSurface.
- *
- * This method exists to avoid leaking the window's SurfaceControl outside WindowManagerService.
+ * Returns {@code true} if the given point is within the window bounds of the given window.
*
- * @param inputSurface The surface for which the touchable region should be set.
- * @param inputWindowHandle The {@link InputWindowHandle} for the input surface.
- * @param windowToken The window whose bounds should be used as the touchable region for the
- * inputSurface.
+ * @param windowToken the window whose bounds should be used for the hit test.
+ * @param displayX the x coordinate of the test point in the display's coordinate space.
+ * @param displayY the y coordinate of the test point in the display's coordinate space.
*/
- public abstract void replaceInputSurfaceTouchableRegionWithWindowCrop(
- @NonNull SurfaceControl inputSurface, @NonNull InputWindowHandle inputWindowHandle,
- @NonNull IBinder windowToken);
+ public abstract boolean isPointInsideWindow(
+ @NonNull IBinder windowToken, int displayId, float displayX, float displayY);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3906a19cee3a..8f1f7ece897b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -118,7 +118,6 @@ import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
@@ -173,6 +172,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Bitmap;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -224,6 +224,7 @@ import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.MergedConfiguration;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.TimeUtils;
@@ -3051,22 +3052,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
-
void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
if (mRecentsAnimationController != null) {
final RecentsAnimationController controller = mRecentsAnimationController;
mRecentsAnimationController = null;
controller.cleanupAnimation(reorderMode);
- // TODO(multi-display): currently only default display support recents animation.
- // Cancel any existing app transition animation running in the legacy transition
- // framework.
- final DisplayContent dc = getDefaultDisplayContentLocked();
- dc.mAppTransition.freeze();
- dc.forAllWindowContainers((wc) -> {
- if (wc.isAnimating(TRANSITION, ANIMATION_TYPE_APP_TRANSITION)) {
- wc.cancelAnimation();
- }
- });
+ // TODO(mult-display): currently only default display support recents animation.
+ getDefaultDisplayContentLocked().mAppTransition.updateBooster();
}
}
@@ -7769,6 +7761,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public Pair<Matrix, MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
+ IBinder token) {
+ return mAccessibilityController
+ .getWindowTransformationMatrixAndMagnificationSpec(token);
+ }
+
+ @Override
public void waitForAllWindowsDrawn(Runnable callback, long timeout, int displayId) {
final WindowContainer container = displayId == INVALID_DISPLAY
? mRoot : mRoot.getDisplayContent(displayId);
@@ -8241,23 +8240,15 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void replaceInputSurfaceTouchableRegionWithWindowCrop(
- @NonNull SurfaceControl inputSurface,
- @NonNull InputWindowHandle inputWindowHandle,
- @NonNull IBinder windowToken) {
+ public boolean isPointInsideWindow(@NonNull IBinder windowToken, int displayId,
+ float displayX, float displayY) {
synchronized (mGlobalLock) {
final WindowState w = mWindowMap.get(windowToken);
- if (w == null) {
- return;
+ if (w == null || w.getDisplayId() != displayId) {
+ return false;
}
- // Make a copy of the InputWindowHandle to avoid leaking the window's
- // SurfaceControl.
- final InputWindowHandle localHandle = new InputWindowHandle(inputWindowHandle);
- localHandle.replaceTouchableRegionWithCrop(w.getSurfaceControl());
- final SurfaceControl.Transaction t = mTransactionFactory.get();
- t.setInputWindowInfo(inputSurface, localHandle);
- t.apply();
- t.close();
+
+ return w.getBounds().contains((int) displayX, (int) displayY);
}
}
}
@@ -8877,16 +8868,18 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState newFocusTarget = displayContent == null
? null : displayContent.findFocusedWindow();
if (newFocusTarget == null) {
- ProtoLog.v(WM_DEBUG_FOCUS, "grantEmbeddedWindowFocus remove request for "
- + "win=%s dropped since no candidate was found",
+ t.setFocusedWindow(null, null, displayId).apply();
+ ProtoLog.v(WM_DEBUG_FOCUS, "grantEmbeddedWindowFocus win=%s"
+ + " dropped focus so setting focus to null since no candidate"
+ + " was found",
embeddedWindow);
return;
}
- t.requestFocusTransfer(newFocusTarget.mInputChannelToken, newFocusTarget.getName(),
- inputToken, embeddedWindow.toString(),
+ t.setFocusedWindow(newFocusTarget.mInputChannelToken, newFocusTarget.getName(),
displayId).apply();
+
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
- "Transfer focus request " + newFocusTarget,
+ "Focus request " + newFocusTarget,
"reason=grantEmbeddedWindowFocus(false)");
}
ProtoLog.v(WM_DEBUG_FOCUS, "grantEmbeddedWindowFocus win=%s grantFocus=%s",
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8a7134e24cf8..7f466f38e96a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8513,6 +8513,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ private boolean isDeviceOwnerUserId(int userId) {
+ synchronized (getLockObject()) {
+ return mOwners.getDeviceOwnerComponent() != null
+ && mOwners.getDeviceOwnerUserId() == userId;
+ }
+ }
+
private boolean isDeviceOwnerPackage(String packageName, int userId) {
synchronized (getLockObject()) {
return mOwners.hasDeviceOwner()
@@ -12117,10 +12124,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ Preconditions.checkCallAuthorization((isProfileOwner(caller)
+ && isManagedProfile(caller.getUserId()))
|| isDefaultDeviceOwner(caller),
- "Caller is not profile owner or device owner;"
- + " only profile owner or device owner may control the preferential"
+ "Caller is not managed profile owner or device owner;"
+ + " only managed profile owner or device owner may control the preferential"
+ " network service");
synchronized (getLockObject()) {
final ActiveAdmin requiredAdmin = getDeviceOrProfileOwnerAdminLocked(
@@ -12147,11 +12155,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ Preconditions.checkCallAuthorization((isProfileOwner(caller)
+ && isManagedProfile(caller.getUserId()))
|| isDefaultDeviceOwner(caller),
- "Caller is not profile owner or device owner;"
- + " only profile owner or device owner may retrieve the preferential"
- + " network service configurations");
+ "Caller is not managed profile owner or device owner;"
+ + " only managed profile owner or device owner may retrieve the "
+ + "preferential network service configurations");
synchronized (getLockObject()) {
final ActiveAdmin requiredAdmin = getDeviceOrProfileOwnerAdminLocked(
caller.getUserId());
@@ -18266,7 +18275,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private void updateNetworkPreferenceForUser(int userId,
List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs) {
- if (!isManagedProfile(userId)) {
+ if (!isManagedProfile(userId) && !isDeviceOwnerUserId(userId)) {
return;
}
List<ProfileNetworkPreference> preferences = new ArrayList<>();
diff --git a/services/proguard.flags b/services/proguard.flags
index 425da6c11177..bad02b47031c 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -33,6 +33,11 @@
public <init>(...);
}
+# Accessed from com.android.compos APEX
+-keep,allowoptimization,allowaccessmodification class com.android.internal.art.ArtStatsLog {
+ public static void write(...);
+}
+
# Binder interfaces
-keep,allowoptimization,allowaccessmodification class * extends android.os.IInterface
-keep,allowoptimization,allowaccessmodification class * extends android.os.IHwInterface
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index 08df4381ad62..19df5a2ddd8b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -89,8 +89,10 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.util.Pair;
import android.view.Display;
import android.view.KeyEvent;
+import android.view.MagnificationSpec;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -145,6 +147,8 @@ public class AbstractAccessibilityServiceConnectionTest {
private static final int USER_ID = 1;
private static final int USER_ID2 = 2;
private static final int INTERACTION_ID = 199;
+ private static final Pair<float[], MagnificationSpec> FAKE_MATRIX_AND_MAG_SPEC =
+ new Pair<>(new float[9], new MagnificationSpec());
private static final int PID = Process.myPid();
private static final long TID = Process.myTid();
private static final int UID = Process.myUid();
@@ -188,6 +192,8 @@ public class AbstractAccessibilityServiceConnectionTest {
.thenReturn(mMockFingerprintGestureDispatcher);
when(mMockSystemSupport.getMagnificationProcessor())
.thenReturn(mMockMagnificationProcessor);
+ when(mMockSystemSupport.getWindowTransformationMatrixAndMagnificationSpec(anyInt()))
+ .thenReturn(FAKE_MATRIX_AND_MAG_SPEC);
PowerManager powerManager =
new PowerManager(mMockContext, mMockIPowerManager, mMockIThermalService, mHandler);
diff --git a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
index d1390c68e130..e68a8a0f3af8 100644
--- a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
@@ -49,10 +49,11 @@ public class DropboxRateLimiterTest {
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
// Different processes and tags should not get rate limited either.
assertFalse(mRateLimiter.shouldRateLimit("tag", "process2").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag2", "process").shouldRateLimit());
- // The 6th entry of the same process should be rate limited.
+ // The 7th entry of the same process should be rate limited.
assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
}
@@ -64,12 +65,13 @@ public class DropboxRateLimiterTest {
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
- // The 6th entry of the same process should be rate limited.
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ // The 7th entry of the same process should be rate limited.
assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
- // After 11 seconds there should be nothing left in the buffer and the same type of entry
+ // After 11 minutes there should be nothing left in the buffer and the same type of entry
// should not get rate limited anymore.
- mClock.setOffsetMillis(11000);
+ mClock.setOffsetMillis(11 * 60 * 1000);
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
}
@@ -86,13 +88,15 @@ public class DropboxRateLimiterTest {
mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
assertEquals(0,
mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
+ assertEquals(0,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
assertEquals(1,
mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
assertEquals(2,
mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
- // After 11 seconds the rate limiting buffer will be cleared and rate limiting will stop.
- mClock.setOffsetMillis(11000);
+ // After 11 minutes the rate limiting buffer will be cleared and rate limiting will stop.
+ mClock.setOffsetMillis(11 * 60 * 1000);
// The first call after rate limiting stops will still return the number of dropped events.
assertEquals(2,
diff --git a/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt b/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
index cb97c9bf91a3..e78f0c77d6b3 100644
--- a/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
@@ -20,9 +20,11 @@ import android.content.Context
import android.content.ContextWrapper
import android.hardware.display.DisplayViewport
import android.hardware.input.InputManagerInternal
+import android.os.IInputConstants
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
import android.view.Display
+import android.view.PointerIcon
import androidx.test.InstrumentationRegistry
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -31,6 +33,7 @@ import org.junit.Rule
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.doAnswer
@@ -38,6 +41,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.junit.MockitoJUnit
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@@ -219,4 +223,23 @@ class InputManagerServiceTests {
secondRequestLatch.await(100, TimeUnit.MILLISECONDS))
verify(native, times(2)).setPointerDisplayId(anyInt())
}
-} \ No newline at end of file
+
+ @Test
+ fun onDisplayRemoved_resetAllAdditionalInputProperties() {
+ localService.setVirtualMousePointerDisplayId(10)
+ localService.setPointerIconVisible(false, 10)
+ verify(native).setPointerIconType(eq(PointerIcon.TYPE_NULL))
+ localService.setPointerAcceleration(5f, 10)
+ verify(native).setPointerAcceleration(eq(5f))
+
+ service.onDisplayRemoved(10)
+ verify(native).displayRemoved(eq(10))
+ verify(native).setPointerIconType(eq(PointerIcon.TYPE_NOT_SPECIFIED))
+ verify(native).setPointerAcceleration(
+ eq(IInputConstants.DEFAULT_POINTER_ACCELERATION.toFloat()))
+
+ localService.setVirtualMousePointerDisplayId(10)
+ verify(native).setPointerDisplayId(eq(10))
+ verifyNoMoreInteractions(native)
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index a227cd3c6f5c..035249e32d74 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -70,6 +70,7 @@ import com.google.common.collect.ImmutableMap;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -516,6 +517,7 @@ public class RecoverableKeyStoreManagerTest {
}
}
+ @Ignore("Causing breakages so ignoring to resolve, b/231667368")
@Test
public void initRecoveryService_alwaysUpdatesCertsWhenTestRootCertIsUsed() throws Exception {
int uid = Binder.getCallingUid();
@@ -539,6 +541,7 @@ public class RecoverableKeyStoreManagerTest {
testRootCertAlias)).isEqualTo(TestData.getInsecureCertPathForEndpoint2());
}
+ @Ignore("Causing breakages so ignoring to resolve, b/231667368")
@Test
public void initRecoveryService_updatesCertsIndependentlyForDifferentRoots() throws Exception {
int uid = Binder.getCallingUid();
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index 20486b3e396d..8167b44ee59d 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -454,14 +454,14 @@ public class SystemConfigTest {
+ " <library \n"
+ " name=\"foo\"\n"
+ " file=\"" + mFooJar + "\"\n"
- + " on-bootclasspath-before=\"Q\"\n"
+ + " on-bootclasspath-before=\"A\"\n"
+ " on-bootclasspath-since=\"W\"\n"
+ " />\n\n"
+ " </permissions>";
parseSharedLibraries(contents);
assertFooIsOnlySharedLibrary();
SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
- assertThat(entry.onBootclasspathBefore).isEqualTo("Q");
+ assertThat(entry.onBootclasspathBefore).isEqualTo("A");
assertThat(entry.onBootclasspathSince).isEqualTo("W");
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 35921585d56f..eb6395b46120 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -39,10 +39,8 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
@@ -50,9 +48,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import android.graphics.Rect;
import android.os.Binder;
@@ -380,7 +376,7 @@ public class AppTransitionTests extends WindowTestsBase {
doReturn(false).when(dc).onDescendantOrientationChanged(any());
final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
dc, "exiting app");
- final ActivityRecord exitingActivity = exitingAppWindow.mActivityRecord;
+ final ActivityRecord exitingActivity= exitingAppWindow.mActivityRecord;
// Wait until everything in animation handler get executed to prevent the exiting window
// from being removed during WindowSurfacePlacer Traversal.
waitUntilHandlersIdle();
@@ -409,41 +405,6 @@ public class AppTransitionTests extends WindowTestsBase {
}
@Test
- public void testDelayWhileRecents() {
- final DisplayContent dc = createNewDisplay(Display.STATE_ON);
- doReturn(false).when(dc).onDescendantOrientationChanged(any());
- final Task task = createTask(dc);
-
- // Simulate activity1 launches activity2.
- final ActivityRecord activity1 = createActivityRecord(task);
- activity1.setVisible(true);
- activity1.mVisibleRequested = false;
- activity1.allDrawn = true;
- final ActivityRecord activity2 = createActivityRecord(task);
- activity2.setVisible(false);
- activity2.mVisibleRequested = true;
- activity2.allDrawn = true;
-
- dc.mClosingApps.add(activity1);
- dc.mOpeningApps.add(activity2);
- dc.prepareAppTransition(TRANSIT_OPEN);
- assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_OPEN));
-
- // Wait until everything in animation handler get executed to prevent the exiting window
- // from being removed during WindowSurfacePlacer Traversal.
- waitUntilHandlersIdle();
-
- // Start recents
- doReturn(true).when(task)
- .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS));
-
- dc.mAppTransitionController.handleAppTransitionReady();
-
- verify(activity1, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
- verify(activity2, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
- }
-
- @Test
public void testGetAnimationStyleResId() {
// Verify getAnimationStyleResId will return as LayoutParams.windowAnimations when without
// specifying window type.
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index e3485deb9080..ec94f8a1829f 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -46,6 +46,14 @@ import java.util.Objects;
* See {@link PhoneAccount}, {@link TelecomManager}.
*/
public final class PhoneAccountHandle implements Parcelable {
+ /**
+ * Expected component name of Telephony phone accounts; ONLY used to determine if we should log
+ * the phone account handle ID.
+ */
+ private static final ComponentName TELEPHONY_COMPONENT_NAME =
+ new ComponentName("com.android.phone",
+ "com.android.services.telephony.TelephonyConnectionService");
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
private final ComponentName mComponentName;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -136,14 +144,23 @@ public final class PhoneAccountHandle implements Parcelable {
@Override
public String toString() {
- // Note: Log.pii called for mId as it can contain personally identifying phone account
- // information such as SIP account IDs.
- return new StringBuilder().append(mComponentName)
- .append(", ")
- .append(Log.pii(mId))
- .append(", ")
- .append(mUserHandle)
- .toString();
+ StringBuilder sb = new StringBuilder()
+ .append(mComponentName)
+ .append(", ");
+
+ if (TELEPHONY_COMPONENT_NAME.equals(mComponentName)) {
+ // Telephony phone account handles are now keyed by subscription id which is not
+ // sensitive.
+ sb.append(mId);
+ } else {
+ // Note: Log.pii called for mId as it can contain personally identifying phone account
+ // information such as SIP account IDs.
+ sb.append(Log.pii(mId));
+ }
+ sb.append(", ");
+ sb.append(mUserHandle);
+
+ return sb.toString();
}
@Override
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e21301eb32af..70fe6b10ef20 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4980,6 +4980,25 @@ public class CarrierConfigManager {
KEY_PREFIX + "use_sip_uri_for_presence_subscribe_bool";
/**
+ * Flag indicating whether or not to use TEL URI when setting the entity uri field and
+ * contact element of each tuple.
+ *
+ * When {@code true}, the device sets the entity uri field and contact element to be
+ * TEL URI. This is done by first searching for the first TEL URI provided in
+ * p-associated-uri header. If there are no TEL URIs in the p-associated-uri header, we will
+ * convert the first SIP URI provided in the header to a TEL URI. If there are no URIs in
+ * the p-associated-uri header, we will then fall back to using the SIM card to generate the
+ * TEL URI.
+ * If {@code false}, the first URI provided in the p-associated-uri header is used,
+ * independent of the URI scheme. If there are no URIs available from p-associated-uri
+ * header, we will try to generate a SIP URI or TEL URI from the information provided by the
+ * SIM card, depending on the information available.
+ * @hide
+ */
+ public static final String KEY_USE_TEL_URI_FOR_PIDF_XML_BOOL =
+ KEY_PREFIX + "use_tel_uri_for_pidf_xml";
+
+ /**
* An integer key associated with the period of time in seconds the non-rcs capability
* information of each contact is cached on the device.
* <p>
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index fa6de1ad2864..ac1f376cf6b5 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -1673,4 +1673,9 @@ public final class DataFailCause {
return UNKNOWN;
}
}
+
+ /** @hide */
+ public static boolean isFailCauseExisting(@DataFailureCause int failCause) {
+ return sFailCauseMap.containsKey(failCause);
+ }
}
diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp
index d4fa1dda8bdf..62e16a5b83de 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/ApkVerityTest/Android.bp
@@ -37,8 +37,8 @@ java_test_host {
"general-tests",
"vts",
],
- data_device_bins: [
- "block_device_writer",
+ target_required: [
+ "block_device_writer_module",
],
data: [
":ApkVerityTestCertDer",
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp
index e5d009dc10fd..fdfa41fd4ca9 100644
--- a/tests/ApkVerityTest/block_device_writer/Android.bp
+++ b/tests/ApkVerityTest/block_device_writer/Android.bp
@@ -24,7 +24,12 @@ package {
}
cc_test {
- name: "block_device_writer",
+ // Depending on how the test runs, the executable may be uploaded to different location.
+ // Before the bug in the file pusher is fixed, workaround by making the name unique.
+ // See b/124718249#comment12.
+ name: "block_device_writer_module",
+ stem: "block_device_writer",
+
srcs: ["block_device_writer.cpp"],
cflags: [
"-D_FILE_OFFSET_BITS=64",
@@ -37,7 +42,22 @@ cc_test {
"libbase",
"libutils",
],
- compile_multilib: "first",
+ // For some reasons, cuttlefish (x86) uses x86_64 test suites for testing. Unfortunately, when
+ // the uploader does not pick up the executable from correct output location. The following
+ // workaround allows the test to:
+ // * upload the 32-bit exectuable for both 32 and 64 bits devices to use
+ // * refer to the same executable name in Java
+ // * no need to force the Java test to be archiecture specific.
+ //
+ // See b/145573317 for details.
+ multilib: {
+ lib32: {
+ suffix: "",
+ },
+ lib64: {
+ suffix: "64", // not really used
+ },
+ },
auto_gen_config: false,
test_suites: [
diff --git a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
index 730daf32f20d..5c2c15b22bb0 100644
--- a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
+++ b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
@@ -32,7 +32,7 @@ import java.util.ArrayList;
* <p>To use this class, please push block_device_writer binary to /data/local/tmp.
* 1. In Android.bp, add:
* <pre>
- * data_device_bins: ["block_device_writer"],
+ * target_required: ["block_device_writer_module"],
* </pre>
* 2. In AndroidText.xml, add:
* <pre>