diff options
34 files changed, 815 insertions, 376 deletions
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java index 0d6a07938e95..e6cdcc0ee742 100644 --- a/core/java/android/accounts/Account.java +++ b/core/java/android/accounts/Account.java @@ -31,6 +31,7 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; +import java.util.Objects; import java.util.Set; /** @@ -86,6 +87,12 @@ public class Account implements Parcelable { if (TextUtils.isEmpty(type)) { throw new IllegalArgumentException("the type must not be empty: " + type); } + if (name.length() > 200) { + throw new IllegalArgumentException("account name is longer than 200 characters"); + } + if (type.length() > 200) { + throw new IllegalArgumentException("account type is longer than 200 characters"); + } this.name = name; this.type = type; this.accessId = accessId; diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java index 5964f71d28db..babeb08caff7 100644 --- a/core/java/android/app/GameManager.java +++ b/core/java/android/app/GameManager.java @@ -135,6 +135,7 @@ public final class GameManager { throw e.rethrowFromSystemServer(); } } + /** * Returns a list of supported game modes for a given package. * <p> @@ -151,4 +152,20 @@ public final class GameManager { } } + /** + * Returns if ANGLE is enabled for a given package. + * <p> + * The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}. + * + * @hide + */ + @UserHandleAware + @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) + public @GameMode boolean isAngleEnabled(@NonNull String packageName) { + try { + return mService.getAngleEnabled(packageName, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl index 4bf8a3f77bca..189f0a2fca23 100644 --- a/core/java/android/app/IGameManagerService.aidl +++ b/core/java/android/app/IGameManagerService.aidl @@ -23,4 +23,5 @@ interface IGameManagerService { int getGameMode(String packageName, int userId); void setGameMode(String packageName, int gameMode, int userId); int[] getAvailableGameModes(String packageName); + boolean getAngleEnabled(String packageName, int userId); }
\ No newline at end of file diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index bbb550fd6343..5a5fac4a7664 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1329,7 +1329,10 @@ public final class BluetoothDevice implements Parcelable, Attributable { if (alias == null) { return getName(); } - return alias; + return alias + .replace('\t', ' ') + .replace('\n', ' ') + .replace('\r', ' '); } catch (RemoteException e) { Log.e(TAG, "", e); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 27027721109d..08e95a267d7f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3195,7 +3195,7 @@ public abstract class Context { * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#O} * or higher are not allowed to start background services from the background. * See - * <a href="{@docRoot}/about/versions/oreo/background"> + * <a href="/about/versions/oreo/background"> * Background Execution Limits</a> * for more details. * @@ -3204,7 +3204,7 @@ public abstract class Context { * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} * or higher are not allowed to start foreground services from the background. * See - * <a href="{@docRoot}/about/versions/12/behavior-changes-12"> + * <a href="/about/versions/12/behavior-changes-12"> * Behavior changes: Apps targeting Android 12 * </a> * for more details. @@ -3258,7 +3258,7 @@ public abstract class Context { * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} * or higher are not allowed to start foreground services from the background. * See - * <a href="{@docRoot}/about/versions/12/behavior-changes-12"> + * <a href="/about/versions/12/behavior-changes-12"> * Behavior changes: Apps targeting Android 12 * </a> * for more details. diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index 1651bfc2db5d..1cceea30868c 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -17,6 +17,7 @@ package android.os; import android.app.Activity; +import android.app.GameManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -113,6 +114,7 @@ public class GraphicsEnvironment { private ClassLoader mClassLoader; private String mLibrarySearchPaths; private String mLibraryPermittedPaths; + private GameManager mGameManager; private int mAngleOptInIndex = -1; @@ -125,6 +127,8 @@ public class GraphicsEnvironment { final ApplicationInfo appInfoWithMetaData = getAppInfoWithMetadata(context, pm, packageName); + mGameManager = context.getSystemService(GameManager.class); + Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers"); setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData); Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); @@ -143,6 +147,23 @@ public class GraphicsEnvironment { } /** + * Query to determine if the Game Mode has enabled ANGLE. + */ + private boolean isAngleEnabledByGameMode(Context context, String packageName) { + try { + final boolean gameModeEnabledAngle = + (mGameManager != null) && mGameManager.isAngleEnabled(packageName); + Log.v(TAG, "ANGLE GameManagerService for " + packageName + ": " + gameModeEnabledAngle); + return gameModeEnabledAngle; + } catch (SecurityException e) { + Log.e(TAG, "Caught exception while querying GameManagerService if ANGLE is enabled " + + "for package: " + packageName); + } + + return false; + } + + /** * Query to determine if ANGLE should be used */ private boolean shouldUseAngle(Context context, Bundle coreSettings, @@ -163,7 +184,9 @@ public class GraphicsEnvironment { Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn); } - return requested; + final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName); + + return requested || gameModeEnabledAngle; } private int getVulkanVersion(PackageManager pm) { @@ -521,16 +544,20 @@ public class GraphicsEnvironment { if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths); - // If the user has set the developer option to something other than default, - // we need to call setAngleInfo() with the package name and the developer - // option value (native/angle/other). Then later when we are actually trying to - // load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before - // and can confidently answer yes/no based on the previously set developer - // option value. - final String devOptIn = getDriverForPackage(context, bundle, packageName); + // We need to call setAngleInfo() with the package name and the developer option value + //(native/angle/other). Then later when we are actually trying to load a driver, + //GraphicsEnv::getShouldUseAngle() has seen the package name before and can confidently + //answer yes/no based on the previously set developer option value. + final String devOptIn; final String[] features = getAngleEglFeatures(context, bundle); - + final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName); + if (gameModeEnabledAngle) { + devOptIn = ANGLE_GL_DRIVER_CHOICE_ANGLE; + } else { + devOptIn = getDriverForPackage(context, bundle, packageName); + } setAngleInfo(paths, packageName, devOptIn, features); + return true; } diff --git a/packages/SystemUI/res/color/settingslib_state_off.xml b/packages/SystemUI/res/color/settingslib_state_off.xml new file mode 100644 index 000000000000..e8218259087d --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_state_off.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + <item android:color="?androidprv:attr/colorAccentSecondaryVariant"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_state_on.xml b/packages/SystemUI/res/color/settingslib_state_on.xml new file mode 100644 index 000000000000..6d2133c5bacf --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_state_on.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + <item android:color="?androidprv:attr/colorAccentPrimary"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_track_off.xml b/packages/SystemUI/res/color/settingslib_track_off.xml new file mode 100644 index 000000000000..21d1dccbf900 --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_track_off.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + <item android:color="?androidprv:attr/colorAccentSecondary"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_track_on.xml b/packages/SystemUI/res/color/settingslib_track_on.xml new file mode 100644 index 000000000000..ba7848a5d23e --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_track_on.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + <item android:color="?androidprv:attr/colorAccentPrimaryVariant"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml index cc44b5e5df38..b1e8c386fe21 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml @@ -49,6 +49,11 @@ /> </FrameLayout> + <!-- We want this to be centered (to align with notches). In order to do that, the following + has to hold (in portrait): + * date_container and privacy_container must have the same width and weight + * header_text_container must be gone + --> <android.widget.Space android:id="@+id/space" android:layout_width="0dp" @@ -75,7 +80,7 @@ android:layout_weight="1" android:gravity="center_vertical|end" > - <include layout="@layout/ongoing_privacy_chip" /> + <include layout="@layout/ongoing_privacy_chip" /> </FrameLayout> </LinearLayout> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index a4c1d94f9176..3b1f4fde109a 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -284,13 +284,13 @@ <!-- Internet Dialog --> <!-- Material next state on color--> - <color name="settingslib_state_on_color">?androidprv:attr/colorAccentPrimary</color> + <color name="settingslib_state_on_color">@color/settingslib_state_on</color> <!-- Material next state off color--> - <color name="settingslib_state_off_color">?androidprv:attr/colorAccentSecondary</color> + <color name="settingslib_state_off_color">@color/settingslib_state_off</color> <!-- Material next track on color--> - <color name="settingslib_track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color> + <color name="settingslib_track_on_color">@color/settingslib_track_on</color> <!-- Material next track off color--> - <color name="settingslib_track_off_color">?androidprv:attr/colorAccentSecondaryVariant</color> + <color name="settingslib_track_off_color">@color/settingslib_track_off</color> <color name="connected_network_primary_color">#191C18</color> <color name="connected_network_secondary_color">#41493D</color> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index a180cc1b5af0..e38e069392c4 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2995,8 +2995,6 @@ <!-- URL for more information about changes in global actions --> <string name="global_actions_change_url" translatable="false"></string> - <!-- Provider Model: Title of the airplane mode in the internet dialog. [CHAR LIMIT=50] --> - <string name="airplane_mode">Airplane mode</string> <!-- Provider Model: Default title of the mobile network in the mobile layout. [CHAR LIMIT=50] --> <string name="mobile_data_settings_title">Mobile data</string> <!-- Provider Model: Summary text separator for preferences including a short description @@ -3007,7 +3005,7 @@ <string name="mobile_data_connection_active">Connected</string> <!-- Provider Model: Summary indicating that a SIM has no mobile data connection [CHAR LIMIT=50] --> - <string name="mobile_data_off_summary">Internet won\u0027t auto\u2011connect</string> + <string name="mobile_data_off_summary">Mobile data won\u0027t auto\u2011connect</string> <!-- Provider Model: Summary indicating that a active SIM and no network available [CHAR LIMIT=50] --> <string name="mobile_data_no_connection">No connection</string> diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index c97a30e6e13e..79ee6a8e8830 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -198,9 +198,11 @@ public class DependencyProvider { @SysUISingleton @Provides static ThemeOverlayApplier provideThemeOverlayManager(Context context, - @Background Executor bgExecutor, OverlayManager overlayManager, + @Background Executor bgExecutor, + @Main Executor mainExecutor, + OverlayManager overlayManager, DumpManager dumpManager) { - return new ThemeOverlayApplier(overlayManager, bgExecutor, + return new ThemeOverlayApplier(overlayManager, bgExecutor, mainExecutor, context.getString(R.string.launcher_overlayable_package), context.getString(R.string.themepicker_overlayable_package), dumpManager); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 19d5fa0ec74f..c88c198f767c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -140,6 +140,10 @@ public class QuickStatusBarHeader extends FrameLayout { mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon); updateResources(); + Configuration config = mContext.getResources().getConfiguration(); + setDatePrivacyContainersWidth(config.orientation == Configuration.ORIENTATION_LANDSCAPE); + setSecurityHeaderContainerVisibility( + config.orientation == Configuration.ORIENTATION_LANDSCAPE); // Don't need to worry about tuner settings for this icon mBatteryRemainingIcon.setIgnoreTunerUpdates(true); @@ -191,6 +195,8 @@ public class QuickStatusBarHeader extends FrameLayout { super.onConfigurationChanged(newConfig); updateResources(); setDatePrivacyContainersWidth(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE); + setSecurityHeaderContainerVisibility( + newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE); } @Override @@ -211,6 +217,10 @@ public class QuickStatusBarHeader extends FrameLayout { mPrivacyContainer.setLayoutParams(lp); } + private void setSecurityHeaderContainerVisibility(boolean landscape) { + mSecurityHeaderView.setVisibility(landscape ? VISIBLE : GONE); + } + private void updateBatteryMode() { if (mConfigShowBatteryEstimate && !mHasCenterCutout) { mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index dfe78de81f7f..62fa3d4ac819 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -391,7 +391,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, level += 1; numLevels += 1; } - return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON, false); + return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON, + !isMobileDataEnabled()); } Drawable getSignalStrengthIcon(Context context, int level, int numLevels, diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 3fbdc23f55d0..8def475c192c 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -33,6 +33,7 @@ import static java.util.Objects.requireNonNull; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.annotation.MainThread; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -261,6 +262,7 @@ public class ScreenshotController { private Bitmap mScreenBitmap; private SaveImageInBackgroundTask mSaveInBgTask; private boolean mScreenshotTakenInPortrait; + private boolean mBlockAttach; private Animator mScreenshotAnimation; private RequestCallback mCurrentRequestCallback; @@ -731,6 +733,7 @@ public class ScreenshotController { new ViewTreeObserver.OnWindowAttachListener() { @Override public void onWindowAttached() { + mBlockAttach = false; decorView.getViewTreeObserver().removeOnWindowAttachListener(this); action.run(); } @@ -747,14 +750,16 @@ public class ScreenshotController { mWindow.setContentView(contentView); } + @MainThread private void attachWindow() { View decorView = mWindow.getDecorView(); - if (decorView.isAttachedToWindow()) { + if (decorView.isAttachedToWindow() || mBlockAttach) { return; } if (DEBUG_WINDOW) { Log.d(TAG, "attachWindow"); } + mBlockAttach = true; mWindowManager.addView(decorView, mWindowLayoutParams); decorView.requestApplyInsets(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index b8334272c157..e8458040f448 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -181,7 +181,8 @@ class NotificationShadeDepthController @Inject constructor( if (shouldApplyShadeBlur()) shadeExpansion else 0f, false)) var combinedBlur = (expansionRadius * INTERACTION_BLUR_FRACTION + animationRadius * ANIMATION_BLUR_FRACTION) - val qsExpandedRatio = qsPanelExpansion * shadeExpansion + val qsExpandedRatio = Interpolators.getNotificationScrimAlpha(qsPanelExpansion, + false /* notification */) * shadeExpansion combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio)) combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress)) var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 7d25aeef6f98..43ec6e6e87d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -587,6 +587,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump if (isNaN(expansionFraction)) { return; } + expansionFraction = Interpolators + .getNotificationScrimAlpha(expansionFraction, false /* notification */); boolean qsBottomVisible = qsPanelBottomY > 0; if (mQsExpansion != expansionFraction || mQsBottomVisible != qsBottomVisible) { mQsExpansion = expansionFraction; diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java index c3b4fbe9a13d..fe0b97056024 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java @@ -132,14 +132,18 @@ public class ThemeOverlayApplier implements Dumpable { /* Target package for each overlay category. */ private final Map<String, String> mCategoryToTargetPackage = new ArrayMap<>(); private final OverlayManager mOverlayManager; - private final Executor mExecutor; + private final Executor mBgExecutor; + private final Executor mMainExecutor; private final String mLauncherPackage; private final String mThemePickerPackage; - public ThemeOverlayApplier(OverlayManager overlayManager, Executor executor, + public ThemeOverlayApplier(OverlayManager overlayManager, + Executor bgExecutor, + Executor mainExecutor, String launcherPackage, String themePickerPackage, DumpManager dumpManager) { mOverlayManager = overlayManager; - mExecutor = executor; + mBgExecutor = bgExecutor; + mMainExecutor = mainExecutor; mLauncherPackage = launcherPackage; mThemePickerPackage = themePickerPackage; mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet( @@ -170,12 +174,13 @@ public class ThemeOverlayApplier implements Dumpable { * Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that * affect sysui will also be applied to the system user. */ - void applyCurrentUserOverlays( + public void applyCurrentUserOverlays( Map<String, OverlayIdentifier> categoryToPackage, FabricatedOverlay[] pendingCreation, int currentUser, - Set<UserHandle> managedProfiles) { - mExecutor.execute(() -> { + Set<UserHandle> managedProfiles, + Runnable onOverlaysApplied) { + mBgExecutor.execute(() -> { // Disable all overlays that have not been specified in the user setting. final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES); @@ -221,6 +226,7 @@ public class ThemeOverlayApplier implements Dumpable { try { mOverlayManager.commit(transaction.build()); + mMainExecutor.execute(onOverlaysApplied); } catch (SecurityException | IllegalStateException e) { Log.e(TAG, "setEnabled failed", e); } diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java index 6af49ff79668..c3327dfc6d4e 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java @@ -521,16 +521,16 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { .map(key -> key + " -> " + categoryToPackage.get(key)).collect( Collectors.joining(", "))); } + Runnable overlaysAppliedRunnable = () -> onOverlaysApplied(); if (mNeedsOverlayCreation) { mNeedsOverlayCreation = false; mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] { mSecondaryOverlay, mNeutralOverlay - }, currentUser, managedProfiles); + }, currentUser, managedProfiles, overlaysAppliedRunnable); } else { mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser, - managedProfiles); + managedProfiles, overlaysAppliedRunnable); } - onOverlaysApplied(); } protected void onOverlaysApplied() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt index a7b14460f925..7f72f194d9d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt @@ -25,6 +25,7 @@ import android.view.View import android.view.ViewRootImpl import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.Interpolators import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.phone.BiometricUnlockController @@ -178,10 +179,21 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { @Test fun setQsPanelExpansion_appliesBlur() { + statusBarState = StatusBarState.KEYGUARD notificationShadeDepthController.qsPanelExpansion = 1f - notificationShadeDepthController.onPanelExpansionChanged(0.5f, tracking = false) + notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false) notificationShadeDepthController.updateBlurCallback.doFrame(0) - verify(blurUtils).applyBlur(any(), anyInt(), eq(false)) + verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false)) + } + + @Test + fun setQsPanelExpansion_easing() { + statusBarState = StatusBarState.KEYGUARD + notificationShadeDepthController.qsPanelExpansion = 0.25f + notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false) + notificationShadeDepthController.updateBlurCallback.doFrame(0) + verify(wallpaperManager).setWallpaperZoomOut(any(), + eq(Interpolators.getNotificationScrimAlpha(0.25f, false /* notifications */))) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index f3420bec5454..47c8806be6d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -705,7 +705,7 @@ public class ScrimControllerTest extends SysuiTestCase { public void qsExpansion_half_clippingQs() { reset(mScrimBehind); mScrimController.setClipsQsScrim(true); - mScrimController.setQsPosition(0.5f, 999 /* value doesn't matter */); + mScrimController.setQsPosition(0.25f, 999 /* value doesn't matter */); finishAnimationsImmediately(); assertScrimAlpha(Map.of( @@ -1136,7 +1136,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void testScrimsVisible_whenShadeVisibleOnLockscreen() { mScrimController.transitionTo(ScrimState.KEYGUARD); - mScrimController.setQsPosition(0.5f, 300); + mScrimController.setQsPosition(0.25f, 300); assertScrimAlpha(Map.of( mScrimBehind, SEMI_TRANSPARENT, diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java index 9c47f19b20c8..e6dc4db34f91 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java @@ -96,6 +96,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { DumpManager mDumpManager; @Mock OverlayManagerTransaction.Builder mTransactionBuilder; + @Mock + Runnable mOnOverlaysApplied; private ThemeOverlayApplier mManager; private boolean mGetOverlayInfoEnabled = true; @@ -103,7 +105,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); - mManager = new ThemeOverlayApplier(mOverlayManager, MoreExecutors.directExecutor(), + mManager = new ThemeOverlayApplier(mOverlayManager, + MoreExecutors.directExecutor(), MoreExecutors.directExecutor(), LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE, mDumpManager) { @Override protected OverlayManagerTransaction.Builder getTransactionBuilder() { @@ -173,7 +176,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Test public void allCategoriesSpecified_allEnabledExclusively() { mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), - TEST_USER_HANDLES); + TEST_USER_HANDLES, mOnOverlaysApplied); verify(mOverlayManager).commit(any()); for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) { @@ -185,7 +188,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Test public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() { mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), - TEST_USER_HANDLES); + TEST_USER_HANDLES, mOnOverlaysApplied); for (Map.Entry<String, OverlayIdentifier> entry : ALL_CATEGORIES_MAP.entrySet()) { if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) { @@ -202,8 +205,9 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { public void allCategoriesSpecified_enabledForAllUserHandles() { Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES); mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), - userHandles); + userHandles, mOnOverlaysApplied); + verify(mOnOverlaysApplied).run(); for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) { verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true), eq(TEST_USER.getIdentifier())); @@ -219,7 +223,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES); mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), - userHandles); + userHandles, mOnOverlaysApplied); for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) { verify(mTransactionBuilder, never()).setEnabled(eq(overlayPackage), eq(true), @@ -233,7 +237,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { mock(FabricatedOverlay.class) }; mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation, - TEST_USER.getIdentifier(), TEST_USER_HANDLES); + TEST_USER.getIdentifier(), TEST_USER_HANDLES, mOnOverlaysApplied); for (FabricatedOverlay overlay : pendingCreation) { verify(mTransactionBuilder).registerFabricatedOverlay(eq(overlay)); @@ -247,7 +251,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID); mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(), - TEST_USER_HANDLES); + TEST_USER_HANDLES, mOnOverlaysApplied); for (OverlayIdentifier overlayPackage : categoryToPackage.values()) { verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true), @@ -264,7 +268,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Test public void zeroCategoriesSpecified_allDisabled() { mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER.getIdentifier(), - TEST_USER_HANDLES); + TEST_USER_HANDLES, mOnOverlaysApplied); for (String category : THEME_CATEGORIES) { verify(mTransactionBuilder).setEnabled( @@ -279,7 +283,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { categoryToPackage.put("blah.category", new OverlayIdentifier("com.example.blah.category")); mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(), - TEST_USER_HANDLES); + TEST_USER_HANDLES, mOnOverlaysApplied); verify(mTransactionBuilder, never()).setEnabled( eq(new OverlayIdentifier("com.example.blah.category")), eq(false), diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java index 07d3fc20983f..d3820f06c645 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java @@ -161,7 +161,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(Map.class); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any()); + .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); // Assert that we received the colors that we were expecting assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) @@ -183,7 +183,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED)); mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK), null, null), WallpaperManager.FLAG_SYSTEM); - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -204,7 +204,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(Map.class); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any()); + .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); // Assert that we received the colors that we were expecting assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) @@ -240,7 +240,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { .isFalse(); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -270,7 +270,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { "android.theme.customization.color_both\":\"0")).isTrue(); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -300,7 +300,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { "android.theme.customization.color_both\":\"1")).isTrue(); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -327,7 +327,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index")) .isFalse(); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -354,7 +354,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index")) .isFalse(); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -382,7 +382,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture()); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -411,14 +411,14 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test public void onProfileAdded_setsTheme() { mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)); - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -428,7 +428,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -438,7 +438,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)); verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -450,7 +450,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { Color.valueOf(Color.BLUE), null); mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM); - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); // Regression test: null events should not reset the internal state and allow colors to be // applied again. @@ -458,11 +458,11 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED)); mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM); verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(), - any()); + any(), any()); mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.GREEN), null, null), WallpaperManager.FLAG_SYSTEM); verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(), - any()); + any(), any()); } @Test @@ -499,7 +499,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture()); // Colors were applied during controller initialization. - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); clearInvocations(mThemeOverlayApplier); } @@ -533,7 +533,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture()); // Colors were applied during controller initialization. - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); clearInvocations(mThemeOverlayApplier); WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), @@ -542,12 +542,12 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { // Defers event because we already have initial colors. verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); // Then event happens after setup phase is over. when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true); mDeviceProvisionedListener.getValue().onUserSetupChanged(); - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -568,11 +568,11 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { Color.valueOf(Color.RED), null); mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM); verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); mWakefulnessLifecycle.dispatchFinishedGoingToSleep(); verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -592,10 +592,10 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { Color.valueOf(Color.RED), null); mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM); verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); mWakefulnessLifecycleObserver.getValue().onFinishedGoingToSleep(); - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -614,7 +614,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(Map.class); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any()); + .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); // Assert that we received the colors that we were expecting assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index a6a8cf018eef..400b084ee966 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -1833,6 +1833,11 @@ public class AccountManagerService + ", skipping since the account already exists"); return false; } + if (accounts.accountsDb.findAllDeAccounts().size() > 100) { + Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() + + ", skipping since more than 50 accounts on device exist"); + return false; + } long accountId = accounts.accountsDb.insertCeAccount(account, password); if (accountId < 0) { Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index af8d7a6a282b..3003c520254b 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -272,6 +272,13 @@ public final class GameManagerService extends IGameManagerService.Stub { "com.android.graphics.intervention.wm.allowDownscale"; /** + * Metadata that can be included in the app manifest to allow/disallow any ANGLE + * interventions. Default value is TRUE. + */ + public static final String METADATA_ANGLE_ALLOW_ANGLE = + "com.android.graphics.intervention.angle.allowAngle"; + + /** * Metadata that needs to be included in the app manifest to OPT-IN to PERFORMANCE mode. * This means the app will assume full responsibility for the experience provided by this * mode and the system will enable no window manager downscaling. @@ -294,6 +301,7 @@ public final class GameManagerService extends IGameManagerService.Stub { private boolean mPerfModeOptedIn; private boolean mBatteryModeOptedIn; private boolean mAllowDownscale; + private boolean mAllowAngle; GamePackageConfiguration(String packageName, int userId) { mPackageName = packageName; @@ -305,10 +313,12 @@ public final class GameManagerService extends IGameManagerService.Stub { mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE); mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE); mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true); + mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true); } else { mPerfModeOptedIn = false; mBatteryModeOptedIn = false; mAllowDownscale = true; + mAllowAngle = true; } } catch (PackageManager.NameNotFoundException e) { // Not all packages are installed, hence ignore those that are not installed yet. @@ -340,14 +350,26 @@ public final class GameManagerService extends IGameManagerService.Stub { public static final String MODE_KEY = "mode"; public static final String SCALING_KEY = "downscaleFactor"; public static final String DEFAULT_SCALING = "1.0"; + public static final String ANGLE_KEY = "useAngle"; private final @GameMode int mGameMode; private final String mScaling; + private final boolean mUseAngle; GameModeConfiguration(KeyValueListParser parser) { mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED); - mScaling = !mAllowDownscale || isGameModeOptedIn(mGameMode) + // isGameModeOptedIn() returns if an app will handle all of the changes necessary + // for a particular game mode. If so, the Android framework (i.e. + // GameManagerService) will not do anything for the app (like window scaling or + // using ANGLE). + mScaling = !mAllowDownscale || willGamePerformOptimizations(mGameMode) ? DEFAULT_SCALING : parser.getString(SCALING_KEY, DEFAULT_SCALING); + // We only want to use ANGLE if: + // - We're allowed to use ANGLE (the app hasn't opted out via the manifest) AND + // - The app has not opted in to performing the work itself AND + // - The Phenotype config has enabled it. + mUseAngle = mAllowAngle && !willGamePerformOptimizations(mGameMode) + && parser.getBoolean(ANGLE_KEY, false); } public int getGameMode() { @@ -358,6 +380,10 @@ public final class GameManagerService extends IGameManagerService.Stub { return mScaling; } + public boolean getUseAngle() { + return mUseAngle; + } + public boolean isValid() { return (mGameMode == GameManager.GAME_MODE_PERFORMANCE || mGameMode == GameManager.GAME_MODE_BATTERY) @@ -368,7 +394,8 @@ public final class GameManagerService extends IGameManagerService.Stub { * @hide */ public String toString() { - return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + "]"; + return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + ",Use Angle:" + + mUseAngle + "]"; } /** @@ -384,13 +411,14 @@ public final class GameManagerService extends IGameManagerService.Stub { } /** - * Gets whether a package has opted into a game mode via its manifest. + * Returns if the app will assume full responsibility for the experience provided by this + * mode. If True, the system will not perform any interventions for the app. * * @return True if the app package has specified in its metadata either: * "com.android.app.gamemode.performance.enabled" or * "com.android.app.gamemode.battery.enabled" with a value of "true" */ - public boolean isGameModeOptedIn(@GameMode int gameMode) { + public boolean willGamePerformOptimizations(@GameMode int gameMode) { return (mBatteryModeOptedIn && gameMode == GameManager.GAME_MODE_BATTERY) || (mPerfModeOptedIn && gameMode == GameManager.GAME_MODE_PERFORMANCE); } @@ -631,7 +659,34 @@ public final class GameManagerService extends IGameManagerService.Stub { mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY); } } - updateCompatModeDownscale(packageName, gameMode); + updateInterventions(packageName, gameMode); + } + + /** + * Get if ANGLE is enabled for the package for the currently enabled game mode. + * Checks that the caller has {@link android.Manifest.permission#MANAGE_GAME_MODE}. + */ + @Override + @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) + public @GameMode boolean getAngleEnabled(String packageName, int userId) + throws SecurityException { + final int gameMode = getGameMode(packageName, userId); + if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) { + return false; + } + + synchronized (mDeviceConfigLock) { + final GamePackageConfiguration config = mConfigs.get(packageName); + if (config == null) { + return false; + } + GamePackageConfiguration.GameModeConfiguration gameModeConfiguration = + config.getGameModeConfiguration(gameMode); + if (gameModeConfiguration == null) { + return false; + } + return gameModeConfiguration.getUseAngle(); + } } /** @@ -753,7 +808,7 @@ public final class GameManagerService extends IGameManagerService.Stub { if (DEBUG) { Slog.v(TAG, dumpDeviceConfigs()); } - if (packageConfig.isGameModeOptedIn(gameMode)) { + if (packageConfig.willGamePerformOptimizations(gameMode)) { disableCompatScale(packageName); return; } @@ -782,6 +837,17 @@ public final class GameManagerService extends IGameManagerService.Stub { return (bitField & modeToBitmask(gameMode)) != 0; } + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + private void updateUseAngle(String packageName, @GameMode int gameMode) { + // TODO (b/188475576): Nothing to do yet. Remove if it's still empty when we're ready to + // ship. + } + + private void updateInterventions(String packageName, @GameMode int gameMode) { + updateCompatModeDownscale(packageName, gameMode); + updateUseAngle(packageName, gameMode); + } + /** * @hide */ @@ -839,11 +905,11 @@ public final class GameManagerService extends IGameManagerService.Stub { if (newGameMode != gameMode) { setGameMode(packageName, newGameMode, userId); } - updateCompatModeDownscale(packageName, gameMode); + updateInterventions(packageName, gameMode); } } } catch (Exception e) { - Slog.e(TAG, "Failed to update compat modes for user: " + userId); + Slog.e(TAG, "Failed to update compat modes for user " + userId + ": " + e); } } @@ -851,7 +917,7 @@ public final class GameManagerService extends IGameManagerService.Stub { final List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(0, userId); return packages.stream().filter(e -> e.applicationInfo != null && e.applicationInfo.category - == ApplicationInfo.CATEGORY_GAME) + == ApplicationInfo.CATEGORY_GAME) .map(e -> e.packageName) .toArray(String[]::new); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 34e2578f7855..3c0fe717a722 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -5295,6 +5295,10 @@ public class AudioService extends IAudioService.Stub // TODO investigate internal users due to deprecation of SDK API /** @see AudioManager#setBluetoothA2dpOn(boolean) */ public void setBluetoothA2dpOn(boolean on) { + if (!checkAudioSettingsPermission("setBluetoothA2dpOn()")) { + return; + } + // for logging only final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); @@ -5320,6 +5324,10 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#startBluetoothSco() */ public void startBluetoothSco(IBinder cb, int targetSdkVersion) { + if (!checkAudioSettingsPermission("startBluetoothSco()")) { + return; + } + final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); final int scoAudioMode = @@ -5342,6 +5350,10 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#startBluetoothScoVirtualCall() */ public void startBluetoothScoVirtualCall(IBinder cb) { + if (!checkAudioSettingsPermission("startBluetoothScoVirtualCall()")) { + return; + } + final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); final String eventSource = new StringBuilder("startBluetoothScoVirtualCall()") diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 140098da5791..a0654ac0f2eb 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2132,6 +2132,13 @@ public class PackageManagerService extends IPackageManager.Stub boolean filterAppAccess(String packageName, int callingUid, int userId); @LiveImplementation(override = LiveImplementation.MANDATORY) void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) + FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent, + String resolvedType, int flags, List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) + ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags, + List<ResolveInfo> query, boolean debug, int userId); } /** @@ -2914,7 +2921,24 @@ public class PackageManagerService extends IPackageManager.Stub } allHomeCandidates.addAll(resolveInfos); - final String packageName = mDefaultAppProvider.getDefaultHome(userId); + String packageName = mDefaultAppProvider.getDefaultHome(userId); + if (packageName == null) { + // Role changes are not and cannot be atomic because its implementation lives inside + // a system app, so when the home role changes, there is a window when the previous + // role holder is removed and the new role holder is granted the preferred activity, + // but hasn't become the role holder yet. However, this case may be easily hit + // because the preferred activity change triggers a broadcast and receivers may try + // to get the default home activity there. So we need to fix it for this time + // window, and an easy workaround is to fallback to the current preferred activity. + final int appId = UserHandle.getAppId(Binder.getCallingUid()); + final boolean filtered = appId >= Process.FIRST_APPLICATION_UID; + FindPreferredActivityBodyResult result = findPreferredActivityInternal( + intent, null, 0, resolveInfos, true, false, false, userId, filtered); + ResolveInfo preferredResolveInfo = result.mPreferredResolveInfo; + if (preferredResolveInfo != null && preferredResolveInfo.activityInfo != null) { + packageName = preferredResolveInfo.activityInfo.packageName; + } + } if (packageName == null) { return null; } @@ -4846,6 +4870,284 @@ public class PackageManagerService extends IPackageManager.Stub } } // switch } + + // The body of findPreferredActivity. + protected FindPreferredActivityBodyResult findPreferredActivityBody( + Intent intent, String resolvedType, int flags, + List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered, + int callingUid, boolean isDeviceProvisioned) { + FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult(); + + flags = updateFlagsForResolve( + flags, userId, callingUid, false /*includeInstantApps*/, + isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, + resolvedType, flags)); + intent = updateIntentForResolve(intent); + + // Try to find a matching persistent preferred activity. + result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent, + resolvedType, flags, query, debug, userId); + + // If a persistent preferred activity matched, use it. + if (result.mPreferredResolveInfo != null) { + return result; + } + + PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); + // Get the list of preferred activities that handle the intent + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); + List<PreferredActivity> prefs = pir != null + ? pir.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, + userId) + : null; + if (prefs != null && prefs.size() > 0) { + + // First figure out how good the original match set is. + // We will only allow preferred activities that came + // from the same match quality. + int match = 0; + + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); + + final int N = query.size(); + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Match for " + ri.activityInfo + + ": 0x" + Integer.toHexString(match)); + } + if (ri.match > match) { + match = ri.match; + } + } + + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match)); + } + match &= IntentFilter.MATCH_CATEGORY_MASK; + final int M = prefs.size(); + for (int i = 0; i < M; i++) { + final PreferredActivity pa = prefs.get(i); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Checking PreferredActivity ds=" + + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>") + + "\n component=" + pa.mPref.mComponent); + pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } + if (pa.mPref.mMatch != match) { + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Skipping bad match " + + Integer.toHexString(pa.mPref.mMatch)); + } + continue; + } + // If it's not an "always" type preferred activity and that's what we're + // looking for, skip it. + if (always && !pa.mPref.mAlways) { + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); + continue; + } + final ActivityInfo ai = getActivityInfo( + pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS + | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, + userId); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Found preferred activity:"); + if (ai != null) { + ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } else { + Slog.v(TAG, " null"); + } + } + final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent) + && !isDeviceProvisioned; + final boolean allowSetMutation = !excludeSetupWizardHomeActivity + && !queryMayBeFiltered; + if (ai == null) { + // Do not remove launcher's preferred activity during SetupWizard + // due to it may not install yet + if (!allowSetMutation) { + continue; + } + + // This previously registered preferred activity + // component is no longer known. Most likely an update + // to the app was installed and in the new version this + // component no longer exists. Clean it up by removing + // it from the preferred activities list, and skip it. + Slog.w(TAG, "Removing dangling preferred activity: " + + pa.mPref.mComponent); + pir.removeFilter(pa); + result.mChanged = true; + continue; + } + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (!ri.activityInfo.applicationInfo.packageName + .equals(ai.applicationInfo.packageName)) { + continue; + } + if (!ri.activityInfo.name.equals(ai.name)) { + continue; + } + + if (removeMatches && allowSetMutation) { + pir.removeFilter(pa); + result.mChanged = true; + if (DEBUG_PREFERRED) { + Slog.v(TAG, "Removing match " + pa.mPref.mComponent); + } + break; + } + + // Okay we found a previously set preferred or last chosen app. + // If the result set is different from when this + // was created, and is not a subset of the preferred set, we need to + // clear it and re-ask the user their preference, if we're looking for + // an "always" type entry. + + if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) { + if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) { + if (allowSetMutation) { + // some components of the set are no longer present in + // the query, but the preferred activity can still be reused + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Result set changed, but PreferredActivity" + + " is still valid as only non-preferred" + + " components were removed for " + intent + + " type " + resolvedType); + } + // remove obsolete components and re-add the up-to-date + // filter + PreferredActivity freshPa = new PreferredActivity(pa, + pa.mPref.mMatch, + pa.mPref.discardObsoleteComponents(query), + pa.mPref.mComponent, + pa.mPref.mAlways); + pir.removeFilter(pa); + pir.addFilter(freshPa); + result.mChanged = true; + } else { + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Do not remove preferred activity"); + } + } + } else { + if (allowSetMutation) { + Slog.i(TAG, + "Result set changed, dropping preferred activity " + + "for " + intent + " type " + + resolvedType); + if (DEBUG_PREFERRED) { + Slog.v(TAG, + "Removing preferred activity since set changed " + + pa.mPref.mComponent); + } + pir.removeFilter(pa); + // Re-add the filter as a "last chosen" entry (!always) + PreferredActivity lastChosen = new PreferredActivity( + pa, pa.mPref.mMatch, null, pa.mPref.mComponent, + false); + pir.addFilter(lastChosen); + result.mChanged = true; + } + result.mPreferredResolveInfo = null; + return result; + } + } + + // Yay! Either the set matched or we're looking for the last chosen + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Returning preferred activity: " + + ri.activityInfo.packageName + "/" + ri.activityInfo.name); + } + result.mPreferredResolveInfo = ri; + return result; + } + } + } + return result; + } + + public final FindPreferredActivityBodyResult findPreferredActivityInternal( + Intent intent, String resolvedType, int flags, + List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { + + final int callingUid = Binder.getCallingUid(); + // Do NOT hold the packages lock; this calls up into the settings provider which + // could cause a deadlock. + final boolean isDeviceProvisioned = + android.provider.Settings.Global.getInt(mContext.getContentResolver(), + android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1; + // Find the preferred activity - the lock is held inside the method. + return findPreferredActivityBody( + intent, resolvedType, flags, query, always, removeMatches, debug, + userId, queryMayBeFiltered, callingUid, isDeviceProvisioned); + } + + public final ResolveInfo findPersistentPreferredActivityLP(Intent intent, + String resolvedType, + int flags, List<ResolveInfo> query, boolean debug, int userId) { + final int N = query.size(); + PersistentPreferredIntentResolver ppir = + mSettings.getPersistentPreferredActivities(userId); + // Get the list of persistent preferred activities that handle the intent + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Looking for persistent preferred activities..."); + } + List<PersistentPreferredActivity> pprefs = ppir != null + ? ppir.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, + userId) + : null; + if (pprefs != null && pprefs.size() > 0) { + final int M = pprefs.size(); + for (int i = 0; i < M; i++) { + final PersistentPreferredActivity ppa = pprefs.get(i); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Checking PersistentPreferredActivity ds=" + + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>") + + "\n component=" + ppa.mComponent); + ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } + final ActivityInfo ai = getActivityInfo(ppa.mComponent, + flags | MATCH_DISABLED_COMPONENTS, userId); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Found persistent preferred activity:"); + if (ai != null) { + ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } else { + Slog.v(TAG, " null"); + } + } + if (ai == null) { + // This previously registered persistent preferred activity + // component is no longer known. Ignore it and do NOT remove it. + continue; + } + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (!ri.activityInfo.applicationInfo.packageName + .equals(ai.applicationInfo.packageName)) { + continue; + } + if (!ri.activityInfo.name.equals(ai.name)) { + continue; + } + // Found a persistent preference that can handle the intent. + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Returning persistent preferred activity: " + + ri.activityInfo.packageName + "/" + ri.activityInfo.name); + } + return ri; + } + } + } + return null; + } } /** @@ -5005,6 +5307,16 @@ public class PackageManagerService extends IPackageManager.Stub super.dump(type, fd, pw, dumpState); } } + public final FindPreferredActivityBodyResult findPreferredActivityBody(Intent intent, + String resolvedType, int flags, List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered, + int callingUid, boolean isDeviceProvisioned) { + synchronized (mLock) { + return super.findPreferredActivityBody(intent, resolvedType, flags, query, always, + removeMatches, debug, userId, queryMayBeFiltered, callingUid, + isDeviceProvisioned); + } + } } /** @@ -5572,6 +5884,28 @@ public class PackageManagerService extends IPackageManager.Stub current.release(); } } + public final FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent, + String resolvedType, int flags, List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { + ThreadComputer current = live(); + try { + return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags, + query, always, removeMatches, debug, userId, queryMayBeFiltered); + } finally { + current.release(); + } + } + public final ResolveInfo findPersistentPreferredActivityLP(Intent intent, + String resolvedType, int flags, List<ResolveInfo> query, boolean debug, + int userId) { + ThreadComputer current = live(); + try { + return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType, + flags, query, debug, userId); + } finally { + current.release(); + } + } } @@ -9068,7 +9402,7 @@ public class PackageManagerService extends IPackageManager.Stub /** * Update given intent when being used to request {@link ResolveInfo}. */ - private Intent updateIntentForResolve(Intent intent) { + private static Intent updateIntentForResolve(Intent intent) { if (intent.getSelector() != null) { intent = intent.getSelector(); } @@ -10240,7 +10574,7 @@ public class PackageManagerService extends IPackageManager.Stub userId); // Find any earlier preferred or last chosen entries and nuke them findPreferredActivityNotLocked( - intent, resolvedType, flags, query, 0, false, true, false, userId); + intent, resolvedType, flags, query, false, true, false, userId); // Add the new activity as the last chosen for this filter addPreferredActivity(filter, match, null, activity, false, userId, "Setting last chosen", false); @@ -10256,7 +10590,7 @@ public class PackageManagerService extends IPackageManager.Stub final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); return findPreferredActivityNotLocked( - intent, resolvedType, flags, query, 0, false, false, false, userId); + intent, resolvedType, flags, query, false, false, false, userId); } private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, @@ -10298,7 +10632,7 @@ public class PackageManagerService extends IPackageManager.Stub // If we have saved a preference for a preferred activity for // this Intent, use that. ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType, - flags, query, r0.priority, true, false, debug, userId, queryMayBeFiltered); + flags, query, true, false, debug, userId, queryMayBeFiltered); if (ri != null) { return ri; } @@ -10411,287 +10745,72 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, + private ResolveInfo findPersistentPreferredActivityLP(Intent intent, + String resolvedType, int flags, List<ResolveInfo> query, boolean debug, int userId) { - final int N = query.size(); - PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId); - // Get the list of persistent preferred activities that handle the intent - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities..."); - List<PersistentPreferredActivity> pprefs = ppir != null - ? ppir.queryIntent(intent, resolvedType, - (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, - userId) - : null; - if (pprefs != null && pprefs.size() > 0) { - final int M = pprefs.size(); - for (int i=0; i<M; i++) { - final PersistentPreferredActivity ppa = pprefs.get(i); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Checking PersistentPreferredActivity ds=" - + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>") - + "\n component=" + ppa.mComponent); - ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } - final ActivityInfo ai = getActivityInfo(ppa.mComponent, - flags | MATCH_DISABLED_COMPONENTS, userId); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Found persistent preferred activity:"); - if (ai != null) { - ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } else { - Slog.v(TAG, " null"); - } - } - if (ai == null) { - // This previously registered persistent preferred activity - // component is no longer known. Ignore it and do NOT remove it. - continue; - } - for (int j=0; j<N; j++) { - final ResolveInfo ri = query.get(j); - if (!ri.activityInfo.applicationInfo.packageName - .equals(ai.applicationInfo.packageName)) { - continue; - } - if (!ri.activityInfo.name.equals(ai.name)) { - continue; - } - // Found a persistent preference that can handle the intent. - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Returning persistent preferred activity: " + - ri.activityInfo.packageName + "/" + ri.activityInfo.name); - } - return ri; - } - } - } - return null; + return mComputer.findPersistentPreferredActivityLP(intent, + resolvedType, + flags, query, debug, userId); } - private boolean isHomeIntent(Intent intent) { + private static boolean isHomeIntent(Intent intent) { return ACTION_MAIN.equals(intent.getAction()) && intent.hasCategory(CATEGORY_HOME) && intent.hasCategory(CATEGORY_DEFAULT); } + + // findPreferredActivityBody returns two items: a "things changed" flag and a + // ResolveInfo, which is the preferred activity itself. + private static class FindPreferredActivityBodyResult { + boolean mChanged; + ResolveInfo mPreferredResolveInfo; + } + + private FindPreferredActivityBodyResult findPreferredActivityInternal( + Intent intent, String resolvedType, int flags, + List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { + return mComputer.findPreferredActivityInternal( + intent, resolvedType, flags, + query, always, + removeMatches, debug, userId, queryMayBeFiltered); + } + ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, - List<ResolveInfo> query, int priority, boolean always, + List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug, int userId) { return findPreferredActivityNotLocked( - intent, resolvedType, flags, query, priority, always, removeMatches, debug, userId, + intent, resolvedType, flags, query, always, removeMatches, debug, userId, UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID); } // TODO: handle preferred activities missing while user has amnesia /** <b>must not hold {@link #mLock}</b> */ ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, - List<ResolveInfo> query, int priority, boolean always, + List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { if (Thread.holdsLock(mLock)) { Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding mLock", new Throwable()); } if (!mUserManager.exists(userId)) return null; - final int callingUid = Binder.getCallingUid(); - // Do NOT hold the packages lock; this calls up into the settings provider which - // could cause a deadlock. - final boolean isDeviceProvisioned = - android.provider.Settings.Global.getInt(mContext.getContentResolver(), - android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1; - flags = updateFlagsForResolve( - flags, userId, callingUid, false /*includeInstantApps*/, - isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, - flags)); - intent = updateIntentForResolve(intent); - // writer - synchronized (mLock) { - // Try to find a matching persistent preferred activity. - ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query, - debug, userId); - // If a persistent preferred activity matched, use it. - if (pri != null) { - return pri; + FindPreferredActivityBodyResult body = findPreferredActivityInternal( + intent, resolvedType, flags, query, always, + removeMatches, debug, userId, queryMayBeFiltered); + if (body.mChanged) { + if (DEBUG_PREFERRED) { + Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions"); } - - PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); - // Get the list of preferred activities that handle the intent - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); - List<PreferredActivity> prefs = pir != null - ? pir.queryIntent(intent, resolvedType, - (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, - userId) - : null; - if (prefs != null && prefs.size() > 0) { - boolean changed = false; - try { - // First figure out how good the original match set is. - // We will only allow preferred activities that came - // from the same match quality. - int match = 0; - - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); - - final int N = query.size(); - for (int j=0; j<N; j++) { - final ResolveInfo ri = query.get(j); - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Match for " + ri.activityInfo - + ": 0x" + Integer.toHexString(match)); - if (ri.match > match) { - match = ri.match; - } - } - - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x" - + Integer.toHexString(match)); - - match &= IntentFilter.MATCH_CATEGORY_MASK; - final int M = prefs.size(); - for (int i=0; i<M; i++) { - final PreferredActivity pa = prefs.get(i); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Checking PreferredActivity ds=" - + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>") - + "\n component=" + pa.mPref.mComponent); - pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } - if (pa.mPref.mMatch != match) { - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match " - + Integer.toHexString(pa.mPref.mMatch)); - continue; - } - // If it's not an "always" type preferred activity and that's what we're - // looking for, skip it. - if (always && !pa.mPref.mAlways) { - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); - continue; - } - final ActivityInfo ai = getActivityInfo( - pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS - | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, - userId); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Found preferred activity:"); - if (ai != null) { - ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } else { - Slog.v(TAG, " null"); - } - } - final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent) - && !isDeviceProvisioned; - final boolean allowSetMutation = !excludeSetupWizardHomeActivity - && !queryMayBeFiltered; - if (ai == null) { - // Do not remove launcher's preferred activity during SetupWizard - // due to it may not install yet - if (!allowSetMutation) { - continue; - } - - // This previously registered preferred activity - // component is no longer known. Most likely an update - // to the app was installed and in the new version this - // component no longer exists. Clean it up by removing - // it from the preferred activities list, and skip it. - Slog.w(TAG, "Removing dangling preferred activity: " - + pa.mPref.mComponent); - pir.removeFilter(pa); - changed = true; - continue; - } - for (int j=0; j<N; j++) { - final ResolveInfo ri = query.get(j); - if (!ri.activityInfo.applicationInfo.packageName - .equals(ai.applicationInfo.packageName)) { - continue; - } - if (!ri.activityInfo.name.equals(ai.name)) { - continue; - } - - if (removeMatches && allowSetMutation) { - pir.removeFilter(pa); - changed = true; - if (DEBUG_PREFERRED) { - Slog.v(TAG, "Removing match " + pa.mPref.mComponent); - } - break; - } - - // Okay we found a previously set preferred or last chosen app. - // If the result set is different from when this - // was created, and is not a subset of the preferred set, we need to - // clear it and re-ask the user their preference, if we're looking for - // an "always" type entry. - - if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) { - if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) { - if (allowSetMutation) { - // some components of the set are no longer present in - // the query, but the preferred activity can still be reused - if (DEBUG_PREFERRED) { - Slog.i(TAG, "Result set changed, but PreferredActivity" - + " is still valid as only non-preferred" - + " components were removed for " + intent - + " type " + resolvedType); - } - // remove obsolete components and re-add the up-to-date - // filter - PreferredActivity freshPa = new PreferredActivity(pa, - pa.mPref.mMatch, - pa.mPref.discardObsoleteComponents(query), - pa.mPref.mComponent, - pa.mPref.mAlways); - pir.removeFilter(pa); - pir.addFilter(freshPa); - changed = true; - } else { - if (DEBUG_PREFERRED) { - Slog.i(TAG, "Do not remove preferred activity"); - } - } - } else { - if (allowSetMutation) { - Slog.i(TAG, - "Result set changed, dropping preferred activity " - + "for " + intent + " type " - + resolvedType); - if (DEBUG_PREFERRED) { - Slog.v(TAG, - "Removing preferred activity since set changed " - + pa.mPref.mComponent); - } - pir.removeFilter(pa); - // Re-add the filter as a "last chosen" entry (!always) - PreferredActivity lastChosen = new PreferredActivity( - pa, pa.mPref.mMatch, null, pa.mPref.mComponent, - false); - pir.addFilter(lastChosen); - changed = true; - } - return null; - } - } - - // Yay! Either the set matched or we're looking for the last chosen - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Returning preferred activity: " - + ri.activityInfo.packageName + "/" + ri.activityInfo.name); - return ri; - } - } - } finally { - if (changed) { - if (DEBUG_PREFERRED) { - Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions"); - } - scheduleWritePackageRestrictionsLocked(userId); - } - } + synchronized (mLock) { + scheduleWritePackageRestrictionsLocked(userId); } } - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "No preferred activity to return"); - return null; + if ((DEBUG_PREFERRED || debug) && body.mPreferredResolveInfo == null) { + Slog.v(TAG, "No preferred activity to return"); + } + return body.mPreferredResolveInfo; } /* @@ -23468,7 +23587,7 @@ public class PackageManagerService extends IPackageManager.Stub final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked( - intent, null, 0, resolveInfos, 0, true, false, false, userId); + intent, null, 0, resolveInfos, true, false, false, userId); final String packageName = preferredResolveInfo != null && preferredResolveInfo.activityInfo != null ? preferredResolveInfo.activityInfo.packageName : null; diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java index cda48063e914..94e551a11dae 100644 --- a/services/core/java/com/android/server/pm/permission/Permission.java +++ b/services/core/java/com/android/server/pm/permission/Permission.java @@ -480,9 +480,10 @@ public final class Permission { r.append("DUP:"); r.append(permissionInfo.name); } - if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) { - // If this is a runtime permission and the owner has changed, or this wasn't a runtime - // permission, then permission state should be cleaned up + if ((permission.isInternal() && ownerChanged) + || (permission.isRuntime() && (ownerChanged || wasNonRuntime))) { + // If this is an internal/runtime permission and the owner has changed, or this wasn't a + // runtime permission, then permission state should be cleaned up. permission.mDefinitionChanged = true; } if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index c11ffb492a93..54a6c678e0da 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1654,7 +1654,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { isRolePermission = permission.isRole(); } final boolean mayRevokeRolePermission = isRolePermission - && mayManageRolePermission(callingUid); + // Allow ourselves to revoke role permissions due to definition changes. + && (callingUid == Process.myUid() || mayManageRolePermission(callingUid)); final boolean isRuntimePermission; synchronized (mLock) { @@ -2332,11 +2333,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int permNum = 0; permNum < numPermissions; permNum++) { final String permName = permissionsToRevoke.get(permNum); + final boolean isInternalPermission; synchronized (mLock) { final Permission bp = mRegistry.getPermission(permName); - if (bp == null || !bp.isRuntime()) { + if (bp == null || !(bp.isInternal() || bp.isRuntime())) { continue; } + isInternalPermission = bp.isInternal(); } mPackageManagerInt.forEachPackage(pkg -> { final String packageName = pkg.getPackageName(); @@ -2356,12 +2359,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (permissionState == PackageManager.PERMISSION_GRANTED && (flags & flagMask) == 0) { final int uid = UserHandle.getUid(userId, appId); - EventLog.writeEvent(0x534e4554, "154505240", uid, - "Revoking permission " + permName + " from package " - + packageName + " due to definition change"); - EventLog.writeEvent(0x534e4554, "168319670", uid, - "Revoking permission " + permName + " from package " - + packageName + " due to definition change"); + if (isInternalPermission) { + EventLog.writeEvent(0x534e4554, "195338390", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + } else { + EventLog.writeEvent(0x534e4554, "154505240", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + EventLog.writeEvent(0x534e4554, "168319670", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + } Slog.e(TAG, "Revoking permission " + permName + " from package " + packageName + " due to definition change"); try { diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 36a854e5374c..28947083854b 100755 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -2304,10 +2304,9 @@ public final class TvInputManagerService extends SystemService { public void requestChannelBrowsable(Uri channelUri, int userId) throws RemoteException { final String callingPackageName = getCallingPackageName(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), + Binder.getCallingUid(), userId, "requestChannelBrowsable"); final long identity = Binder.clearCallingIdentity(); - final int callingUid = Binder.getCallingUid(); - final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, - userId, "requestChannelBrowsable"); try { Intent intent = new Intent(TvContract.ACTION_CHANNEL_BROWSABLE_REQUESTED); List<ResolveInfo> list = getContext().getPackageManager() diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java index 4d86c8716bf1..8840057cc552 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -182,7 +182,14 @@ public class GameManagerServiceTests { } private void mockDeviceConfigPerformance() { - String configString = "mode=2,downscaleFactor=0.5"; + String configString = "mode=2,downscaleFactor=0.5,useAngle=false"; + when(DeviceConfig.getProperty(anyString(), anyString())) + .thenReturn(configString); + } + + // ANGLE will be disabled for most apps, so treat enabling ANGLE as a special case. + private void mockDeviceConfigPerformanceEnableAngle() { + String configString = "mode=2,downscaleFactor=0.5,useAngle=true"; when(DeviceConfig.getProperty(anyString(), anyString())) .thenReturn(configString); } @@ -212,7 +219,8 @@ public class GameManagerServiceTests { } private void mockGameModeOptInAll() throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); Bundle metaDataBundle = new Bundle(); metaDataBundle.putBoolean( GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true); @@ -224,7 +232,8 @@ public class GameManagerServiceTests { } private void mockGameModeOptInPerformance() throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); Bundle metaDataBundle = new Bundle(); metaDataBundle.putBoolean( GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true); @@ -234,7 +243,8 @@ public class GameManagerServiceTests { } private void mockGameModeOptInBattery() throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); Bundle metaDataBundle = new Bundle(); metaDataBundle.putBoolean( GameManagerService.GamePackageConfiguration.METADATA_BATTERY_MODE_ENABLE, true); @@ -244,7 +254,8 @@ public class GameManagerServiceTests { } private void mockInterventionAllowDownscaleTrue() throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); Bundle metaDataBundle = new Bundle(); metaDataBundle.putBoolean( GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, true); @@ -254,7 +265,8 @@ public class GameManagerServiceTests { } private void mockInterventionAllowDownscaleFalse() throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); Bundle metaDataBundle = new Bundle(); metaDataBundle.putBoolean( GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, false); @@ -263,6 +275,27 @@ public class GameManagerServiceTests { .thenReturn(applicationInfo); } + private void mockInterventionAllowAngleTrue() throws Exception { + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); + Bundle metaDataBundle = new Bundle(); + metaDataBundle.putBoolean( + GameManagerService.GamePackageConfiguration.METADATA_ANGLE_ALLOW_ANGLE, true); + when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) + .thenReturn(applicationInfo); + } + + private void mockInterventionAllowAngleFalse() throws Exception { + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); + Bundle metaDataBundle = new Bundle(); + metaDataBundle.putBoolean( + GameManagerService.GamePackageConfiguration.METADATA_ANGLE_ALLOW_ANGLE, false); + applicationInfo.metaData = metaDataBundle; + when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) + .thenReturn(applicationInfo); + } + /** * By default game mode is not supported. */ @@ -427,6 +460,19 @@ public class GameManagerServiceTests { assertEquals(config.getGameModeConfiguration(gameMode).getScaling(), scaling); } + private void checkAngleEnabled(GameManagerService gameManagerService, int gameMode, + boolean angleEnabled) { + gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + + // Validate GamePackageConfiguration returns the correct value. + GameManagerService.GamePackageConfiguration config = + gameManagerService.getConfig(mPackageName); + assertEquals(config.getGameModeConfiguration(gameMode).getUseAngle(), angleEnabled); + + // Validate GameManagerService.getAngleEnabled() returns the correct value. + assertEquals(gameManagerService.getAngleEnabled(mPackageName, USER_ID_1), angleEnabled); + } + /** * Phenotype device config exists, but is only propagating the default value. */ @@ -592,6 +638,50 @@ public class GameManagerServiceTests { } /** + * PERFORMANCE game mode is configured through Phenotype. The app hasn't specified any metadata. + */ + @Test + public void testInterventionAllowAngleDefault() throws Exception { + GameManagerService gameManagerService = new GameManagerService(mMockContext); + gameManagerService.onUserStarting(USER_ID_1); + mockDeviceConfigPerformance(); + mockModifyGameModeGranted(); + checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, false); + } + + /** + * PERFORMANCE game mode is configured through Phenotype. The app has opted-out of ANGLE. + */ + @Test + public void testInterventionAllowAngleFalse() throws Exception { + GameManagerService gameManagerService = new GameManagerService(mMockContext); + gameManagerService.onUserStarting(USER_ID_1); + mockDeviceConfigPerformanceEnableAngle(); + mockInterventionAllowAngleFalse(); + mockModifyGameModeGranted(); + checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, false); + } + + /** + * PERFORMANCE game mode is configured through Phenotype. The app has redundantly specified + * the ANGLE metadata default value of "true". + */ + @Test + public void testInterventionAllowAngleTrue() throws Exception { + mockDeviceConfigPerformanceEnableAngle(); + mockInterventionAllowAngleTrue(); + + GameManagerService gameManagerService = new GameManagerService(mMockContext); + gameManagerService.onUserStarting(USER_ID_1); + mockModifyGameModeGranted(); + gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); + assertEquals(GameManager.GAME_MODE_PERFORMANCE, + gameManagerService.getGameMode(mPackageName, USER_ID_1)); + + checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, true); + } + + /** * PERFORMANCE game mode is configured through Phenotype, but the app has also opted into the * same mode. No interventions for this game mode should be available in this case. */ diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index a427ed612b31..bc0a14667307 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -23,6 +23,8 @@ import android.os.Build; import android.os.Bundle; import android.util.ArrayMap; +import com.android.internal.annotations.GuardedBy; + import java.util.Collections; import java.util.List; import java.util.Map; @@ -115,6 +117,7 @@ public final class Phone { public static final int SDK_VERSION_R = 30; // A Map allows us to track each Call by its Telecom-specified call ID + @GuardedBy("mLock") private final Map<String, Call> mCallByTelecomCallId = new ArrayMap<>(); // A List allows us to keep the Calls in a stable iteration order so that casually developed @@ -139,6 +142,8 @@ public final class Phone { */ private final int mTargetSdkVersion; + private final Object mLock = new Object(); + Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) { mInCallAdapter = adapter; mCallingPackage = callingPackage; @@ -152,12 +157,16 @@ public final class Phone { return; } - Call call = mCallByTelecomCallId.get(parcelableCall.getId()); + Call call = getCallById(parcelableCall.getId()); if (call == null) { call = new Call(this, parcelableCall.getId(), mInCallAdapter, parcelableCall.getState(), mCallingPackage, mTargetSdkVersion); - mCallByTelecomCallId.put(parcelableCall.getId(), call); - mCalls.add(call); + + synchronized (mLock) { + mCallByTelecomCallId.put(parcelableCall.getId(), call); + mCalls.add(call); + } + checkCallTree(parcelableCall); call.internalUpdate(parcelableCall, mCallByTelecomCallId); fireCallAdded(call); @@ -169,8 +178,10 @@ public final class Phone { } final void internalRemoveCall(Call call) { - mCallByTelecomCallId.remove(call.internalGetCallId()); - mCalls.remove(call); + synchronized (mLock) { + mCallByTelecomCallId.remove(call.internalGetCallId()); + mCalls.remove(call); + } InCallService.VideoCall videoCall = call.getVideoCall(); if (videoCall != null) { @@ -183,14 +194,14 @@ public final class Phone { if (mTargetSdkVersion < SDK_VERSION_R && parcelableCall.getState() == Call.STATE_AUDIO_PROCESSING) { Log.i(this, "removing audio processing call during update for sdk compatibility"); - Call call = mCallByTelecomCallId.get(parcelableCall.getId()); + Call call = getCallById(parcelableCall.getId()); if (call != null) { internalRemoveCall(call); } return; } - Call call = mCallByTelecomCallId.get(parcelableCall.getId()); + Call call = getCallById(parcelableCall.getId()); if (call != null) { checkCallTree(parcelableCall); call.internalUpdate(parcelableCall, mCallByTelecomCallId); @@ -207,8 +218,14 @@ public final class Phone { } } + Call getCallById(String callId) { + synchronized (mLock) { + return mCallByTelecomCallId.get(callId); + } + } + final void internalSetPostDialWait(String telecomId, String remaining) { - Call call = mCallByTelecomCallId.get(telecomId); + Call call = getCallById(telecomId); if (call != null) { call.internalSetPostDialWait(remaining); } @@ -222,7 +239,7 @@ public final class Phone { } final Call internalGetCallByTelecomId(String telecomId) { - return mCallByTelecomCallId.get(telecomId); + return getCallById(telecomId); } final void internalBringToForeground(boolean showDialpad) { @@ -241,35 +258,35 @@ public final class Phone { } final void internalOnConnectionEvent(String telecomId, String event, Bundle extras) { - Call call = mCallByTelecomCallId.get(telecomId); + Call call = getCallById(telecomId); if (call != null) { call.internalOnConnectionEvent(event, extras); } } final void internalOnRttUpgradeRequest(String callId, int requestId) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnRttUpgradeRequest(requestId); } } final void internalOnRttInitiationFailure(String callId, int reason) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnRttInitiationFailure(reason); } } final void internalOnHandoverFailed(String callId, int error) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnHandoverFailed(error); } } final void internalOnHandoverComplete(String callId) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnHandoverComplete(); } |