diff options
42 files changed, 1234 insertions, 554 deletions
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index eb59f0f59be1..da26930ca727 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -409,6 +409,11 @@ public final class SystemUiDeviceConfigFlags { */ public static final String BACK_GESTURE_SLOP_MULTIPLIER = "back_gesture_slop_multiplier"; + /** + * (long) Screenshot keychord delay (how long the buttons must be pressed), in ms + */ + public static final String SCREENSHOT_KEYCHORD_DELAY = "screenshot_keychord_delay"; + private SystemUiDeviceConfigFlags() { } } diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 1803027743f6..6fc702e4a068 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -29,6 +29,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -215,6 +217,7 @@ public class LocationManager { * @see #EXTRA_PROVIDER_ENABLED * @see #isProviderEnabled(String) */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED"; /** @@ -243,6 +246,7 @@ public class LocationManager { * @see #EXTRA_LOCATION_ENABLED * @see #isLocationEnabled() */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED"; /** diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index d1149d37d431..f4c865e1d131 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -21,7 +21,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.settings.UserContextProvider; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -38,7 +38,7 @@ import java.util.Set; * * NOTE: Clients of this class should take care to pass in the correct user context when querying * settings, otherwise you will always read/write for user 0 which is almost never what you want. - * See {@link CurrentUserContextTracker} for a simple way to get the current context + * See {@link UserContextProvider} for a simple way to get the current context */ public final class Prefs { private Prefs() {} // no instantation diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index d213ac1132bb..3e64749c0dce 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -130,7 +130,7 @@ import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; import com.android.systemui.plugins.GlobalActionsPanelPlugin; -import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -252,7 +252,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final RingerModeTracker mRingerModeTracker; private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms private Handler mMainHandler; - private CurrentUserContextTracker mCurrentUserContextTracker; + private UserContextProvider mUserContextProvider; @VisibleForTesting boolean mShowLockScreenCardsAndControls = false; @@ -313,7 +313,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, UiEventLogger uiEventLogger, RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler, ControlsComponent controlsComponent, - CurrentUserContextTracker currentUserContextTracker) { + UserContextProvider userContextProvider) { mContext = context; mWindowManagerFuncs = windowManagerFuncs; mAudioManager = audioManager; @@ -342,7 +342,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mControlsControllerOptional = controlsComponent.getControlsController(); mSysUiState = sysUiState; mMainHandler = handler; - mCurrentUserContextTracker = currentUserContextTracker; + mUserContextProvider = userContextProvider; // receive broadcasts IntentFilter filter = new IntentFilter(); @@ -436,7 +436,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, String[] preferredControlsPackages = mContext.getResources() .getStringArray(com.android.systemui.R.array.config_controlsPreferredPackages); - SharedPreferences prefs = mCurrentUserContextTracker.getCurrentUserContext() + SharedPreferences prefs = mUserContextProvider.getUserContext() .getSharedPreferences(PREFS_CONTROLS_FILE, Context.MODE_PRIVATE); Set<String> seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, Collections.emptySet()); diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java index 8ec3db59117d..3bf118d1f39f 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java @@ -40,7 +40,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.LongRunning; -import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import java.io.IOException; @@ -79,12 +79,12 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis private final Executor mLongExecutor; private final UiEventLogger mUiEventLogger; private final NotificationManager mNotificationManager; - private final CurrentUserContextTracker mUserContextTracker; + private final UserContextProvider mUserContextTracker; @Inject public RecordingService(RecordingController controller, @LongRunning Executor executor, UiEventLogger uiEventLogger, NotificationManager notificationManager, - CurrentUserContextTracker userContextTracker, KeyguardDismissUtil keyguardDismissUtil) { + UserContextProvider userContextTracker, KeyguardDismissUtil keyguardDismissUtil) { mController = controller; mLongExecutor = executor; mUiEventLogger = uiEventLogger; @@ -120,7 +120,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis String action = intent.getAction(); Log.d(TAG, "onStartCommand " + action); - int mCurrentUserId = mUserContextTracker.getCurrentUserContext().getUserId(); + int mCurrentUserId = mUserContextTracker.getUserContext().getUserId(); UserHandle currentUser = new UserHandle(mCurrentUserId); switch (action) { case ACTION_START: @@ -136,7 +136,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis setTapsVisible(mShowTaps); mRecorder = new ScreenMediaRecorder( - mUserContextTracker.getCurrentUserContext(), + mUserContextTracker.getUserContext(), mCurrentUserId, mAudioSource, this @@ -156,7 +156,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis // we want to post the notifications for that user, which is NOT current user int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); if (userId == -1) { - userId = mUserContextTracker.getCurrentUserContext().getUserId(); + userId = mUserContextTracker.getUserContext().getUserId(); } Log.d(TAG, "notifying for user " + userId); stopRecording(userId); diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java index dc47ab4dff63..2b62a29587e6 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java @@ -35,7 +35,7 @@ import android.widget.Spinner; import android.widget.Switch; import com.android.systemui.R; -import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.settings.UserContextProvider; import java.util.ArrayList; import java.util.List; @@ -51,7 +51,7 @@ public class ScreenRecordDialog extends Activity { private static final String TAG = "ScreenRecordDialog"; private final RecordingController mController; - private final CurrentUserContextTracker mCurrentUserContextTracker; + private final UserContextProvider mUserContextProvider; private Switch mTapsSwitch; private Switch mAudioSwitch; private Spinner mOptions; @@ -59,9 +59,9 @@ public class ScreenRecordDialog extends Activity { @Inject public ScreenRecordDialog(RecordingController controller, - CurrentUserContextTracker currentUserContextTracker) { + UserContextProvider userContextProvider) { mController = controller; - mCurrentUserContextTracker = currentUserContextTracker; + mUserContextProvider = userContextProvider; } @Override @@ -108,7 +108,7 @@ public class ScreenRecordDialog extends Activity { } private void requestScreenCapture() { - Context userContext = mCurrentUserContextTracker.getCurrentUserContext(); + Context userContext = mUserContextProvider.getUserContext(); boolean showTaps = mTapsSwitch.isChecked(); ScreenRecordingAudioSource audioMode = mAudioSwitch.isChecked() ? (ScreenRecordingAudioSource) mOptions.getSelectedItem() diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt deleted file mode 100644 index d7c4caaa4f9d..000000000000 --- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.settings - -import android.content.ContentResolver -import android.content.Context -import android.os.UserHandle -import androidx.annotation.VisibleForTesting -import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.util.Assert -import java.lang.IllegalStateException - -/** - * Tracks a reference to the context for the current user - * - * Constructor is injected at SettingsModule - */ -class CurrentUserContextTracker internal constructor( - private val sysuiContext: Context, - broadcastDispatcher: BroadcastDispatcher -) : CurrentUserContentResolverProvider { - private val userTracker: CurrentUserTracker - private var initialized = false - - private var _curUserContext: Context? = null - val currentUserContext: Context - get() { - if (!initialized) { - throw IllegalStateException("Must initialize before getting context") - } - return _curUserContext!! - } - - override val currentUserContentResolver: ContentResolver - get() = currentUserContext.contentResolver - - init { - userTracker = object : CurrentUserTracker(broadcastDispatcher) { - override fun onUserSwitched(newUserId: Int) { - handleUserSwitched(newUserId) - } - } - } - - fun initialize() { - initialized = true - userTracker.startTracking() - _curUserContext = makeUserContext(userTracker.currentUserId) - } - - @VisibleForTesting - fun handleUserSwitched(newUserId: Int) { - _curUserContext = makeUserContext(newUserId) - } - - private fun makeUserContext(uid: Int): Context { - Assert.isMainThread() - return sysuiContext.createContextAsUser(UserHandle.of(uid), 0) - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt index 9d05843b42bf..e0c0c15cba31 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt @@ -18,7 +18,10 @@ package com.android.systemui.settings import android.content.ContentResolver -interface CurrentUserContentResolverProvider { +/** + * Implemented by [UserTrackerImpl]. + */ +interface UserContentResolverProvider { - val currentUserContentResolver: ContentResolver + val userContentResolver: ContentResolver }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt new file mode 100644 index 000000000000..27af15222327 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.settings + +import android.content.Context + +/** + * Implemented by [UserTrackerImpl]. + */ +interface UserContextProvider { + val userContext: Context +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt new file mode 100644 index 000000000000..26d408fe4ab7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.settings + +import android.content.Context +import android.content.pm.UserInfo +import android.os.UserHandle +import java.util.concurrent.Executor + +/** + * User tracker for SystemUI. + * + * This tracker provides async access to current user information, as well as callbacks for + * user/profile change. + */ +interface UserTracker : UserContentResolverProvider, UserContextProvider { + + /** + * Current user's id. + */ + val userId: Int + + /** + * [UserHandle] for current user + */ + val userHandle: UserHandle + + /** + * List of profiles associated with the current user. + */ + val userProfiles: List<UserInfo> + + /** + * Add a [Callback] to be notified of chances, on a particular [Executor] + */ + fun addCallback(callback: Callback, executor: Executor) + + /** + * Remove a [Callback] previously added. + */ + fun removeCallback(callback: Callback) + + /** + * Ćallback for notifying of changes. + */ + interface Callback { + + /** + * Notifies that the current user has changed. + */ + @JvmDefault + fun onUserChanged(newUser: Int, userContext: Context) {} + + /** + * Notifies that the current user's profiles have changed. + */ + @JvmDefault + fun onProfilesChanged(profiles: List<UserInfo>) {} + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt new file mode 100644 index 000000000000..4cc0eeee712c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.settings + +import android.content.BroadcastReceiver +import android.content.ContentResolver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.pm.UserInfo +import android.os.Handler +import android.os.UserHandle +import android.os.UserManager +import android.util.Log +import androidx.annotation.GuardedBy +import androidx.annotation.WorkerThread +import com.android.systemui.Dumpable +import com.android.systemui.dump.DumpManager +import com.android.systemui.util.Assert +import java.io.FileDescriptor +import java.io.PrintWriter +import java.lang.IllegalStateException +import java.lang.ref.WeakReference +import java.util.concurrent.Executor +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +/** + * SystemUI cache for keeping track of the current user and associated values. + * + * The values provided asynchronously are NOT copies, but shared among all requesters. Do not + * modify them. + * + * This class purposefully doesn't use [BroadcastDispatcher] in order to receive the broadcast as + * soon as possible (and reduce its dependency graph). + * Other classes that want to listen to the broadcasts listened here SHOULD + * subscribe to this class instead. + * + * @see UserTracker + * + * Class constructed and initialized in [SettingsModule]. + */ +class UserTrackerImpl internal constructor( + private val context: Context, + private val userManager: UserManager, + private val dumpManager: DumpManager, + private val backgroundHandler: Handler +) : UserTracker, Dumpable, BroadcastReceiver() { + + companion object { + private const val TAG = "UserTrackerImpl" + } + + var initialized = false + private set + + private val mutex = Any() + + override var userId: Int by SynchronizedDelegate(context.userId) + private set + + override var userHandle: UserHandle by SynchronizedDelegate(context.user) + private set + + override var userContext: Context by SynchronizedDelegate(context) + private set + + override val userContentResolver: ContentResolver + get() = userContext.contentResolver + + /** + * Returns a [List<UserInfo>] of all profiles associated with the current user. + * + * The list returned is not a copy, so a copy should be made if its elements need to be + * modified. + */ + override var userProfiles: List<UserInfo> by SynchronizedDelegate(emptyList()) + private set + + @GuardedBy("callbacks") + private val callbacks: MutableList<DataItem> = ArrayList() + + fun initialize(startingUser: Int) { + if (initialized) { + return + } + initialized = true + setUserIdInternal(startingUser) + + val filter = IntentFilter().apply { + addAction(Intent.ACTION_USER_SWITCHED) + addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) + addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED) + } + context.registerReceiverForAllUsers(this, filter, null /* permission */, backgroundHandler) + + dumpManager.registerDumpable(TAG, this) + } + + override fun onReceive(context: Context, intent: Intent) { + when (intent.action) { + Intent.ACTION_USER_SWITCHED -> { + handleSwitchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)) + } + Intent.ACTION_MANAGED_PROFILE_AVAILABLE, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE -> { + handleProfilesChanged() + } + } + } + + private fun setUserIdInternal(user: Int): Pair<Context, List<UserInfo>> { + val profiles = userManager.getProfiles(user) + val handle = UserHandle(user) + val ctx = context.createContextAsUser(handle, 0) + + synchronized(mutex) { + userId = user + userHandle = handle + userContext = ctx + userProfiles = profiles.map { UserInfo(it) } + } + return ctx to profiles + } + + @WorkerThread + private fun handleSwitchUser(newUser: Int) { + Assert.isNotMainThread() + if (newUser == UserHandle.USER_NULL) { + Log.w(TAG, "handleSwitchUser - Couldn't get new id from intent") + return + } + + if (newUser == userId) return + Log.i(TAG, "Switching to user $newUser") + + val (ctx, profiles) = setUserIdInternal(newUser) + + notifySubscribers { + onUserChanged(newUser, ctx) + onProfilesChanged(profiles) + } + } + + @WorkerThread + private fun handleProfilesChanged() { + Assert.isNotMainThread() + + val profiles = userManager.getProfiles(userId) + synchronized(mutex) { + userProfiles = profiles.map { UserInfo(it) } // save a "deep" copy + } + notifySubscribers { + onProfilesChanged(profiles) + } + } + + override fun addCallback(callback: UserTracker.Callback, executor: Executor) { + synchronized(callbacks) { + callbacks.add(DataItem(WeakReference(callback), executor)) + } + } + + override fun removeCallback(callback: UserTracker.Callback) { + synchronized(callbacks) { + callbacks.removeIf { it.sameOrEmpty(callback) } + } + } + + private inline fun notifySubscribers(crossinline action: UserTracker.Callback.() -> Unit) { + val list = synchronized(callbacks) { + callbacks.toList() + } + list.forEach { + if (it.callback.get() != null) { + it.executor.execute { + it.callback.get()?.action() + } + } + } + } + + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { + pw.println("Initialized: $initialized") + if (initialized) { + pw.println("userId: $userId") + val ids = userProfiles.map { it.id } + pw.println("userProfiles: $ids") + } + val list = synchronized(callbacks) { + callbacks.toList() + } + pw.println("Callbacks:") + list.forEach { + it.callback.get()?.let { + pw.println(" $it") + } + } + } + + private class SynchronizedDelegate<T : Any>( + private var value: T + ) : ReadWriteProperty<UserTrackerImpl, T> { + + @GuardedBy("mutex") + override fun getValue(thisRef: UserTrackerImpl, property: KProperty<*>): T { + if (!thisRef.initialized) { + throw IllegalStateException("Must initialize before getting ${property.name}") + } + return synchronized(thisRef.mutex) { value } + } + + @GuardedBy("mutex") + override fun setValue(thisRef: UserTrackerImpl, property: KProperty<*>, value: T) { + synchronized(thisRef.mutex) { this.value = value } + } + } +} + +private data class DataItem( + val callback: WeakReference<UserTracker.Callback>, + val executor: Executor +) { + fun sameOrEmpty(other: UserTracker.Callback): Boolean { + return callback.get()?.equals(other) ?: true + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java b/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java index b1ed77275187..7084d3ffc9ff 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java +++ b/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java @@ -16,12 +16,18 @@ package com.android.systemui.settings.dagger; +import android.app.ActivityManager; import android.content.Context; +import android.os.Handler; +import android.os.UserManager; -import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.settings.CurrentUserContentResolverProvider; -import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dump.DumpManager; +import com.android.systemui.settings.UserContentResolverProvider; +import com.android.systemui.settings.UserContextProvider; +import com.android.systemui.settings.UserTracker; +import com.android.systemui.settings.UserTrackerImpl; import dagger.Binds; import dagger.Module; @@ -33,22 +39,27 @@ import dagger.Provides; @Module public abstract class SettingsModule { - /** - * Provides and initializes a CurrentUserContextTracker - */ + + @Binds + @SysUISingleton + abstract UserContextProvider bindUserContextProvider(UserTracker tracker); + + @Binds + @SysUISingleton + abstract UserContentResolverProvider bindUserContentResolverProvider( + UserTracker tracker); + @SysUISingleton @Provides - static CurrentUserContextTracker provideCurrentUserContextTracker( + static UserTracker provideUserTracker( Context context, - BroadcastDispatcher broadcastDispatcher) { - CurrentUserContextTracker tracker = - new CurrentUserContextTracker(context, broadcastDispatcher); - tracker.initialize(); + UserManager userManager, + DumpManager dumpManager, + @Background Handler handler + ) { + int startingUser = ActivityManager.getCurrentUser(); + UserTrackerImpl tracker = new UserTrackerImpl(context, userManager, dumpManager, handler); + tracker.initialize(startingUser); return tracker; } - - @Binds - @SysUISingleton - abstract CurrentUserContentResolverProvider bindCurrentUserContentResolverTracker( - CurrentUserContextTracker tracker); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java index eca4c8082dfe..0df69a0a1f43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java @@ -185,6 +185,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim mAlertEntries.put(entry.getKey(), alertEntry); onAlertEntryAdded(alertEntry); entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); + entry.setIsAlerting(true); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 387247eb6c5b..8ce9d944b865 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -177,6 +177,7 @@ public final class NotificationEntry extends ListEntry { @Nullable private Long mPendingAnimationDuration; private boolean mIsMarkedForUserTriggeredMovement; private boolean mShelfIconVisible; + private boolean mIsAlerting; /** * @param sbn the StatusBarNotification from system server @@ -955,6 +956,14 @@ public final class NotificationEntry extends ListEntry { mIsMarkedForUserTriggeredMovement = marked; } + public void setIsAlerting(boolean isAlerting) { + mIsAlerting = isAlerting; + } + + public boolean isAlerting() { + return mIsAlerting; + } + /** Information about a suggestion that is being edited. */ public static class EditedSuggestionInfo { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 6d01324f1b7b..f3ed95bd2d76 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -34,7 +34,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -127,7 +127,7 @@ public interface NotificationsModule { LauncherApps launcherApps, ShortcutManager shortcutManager, ChannelEditorDialogController channelEditorDialogController, - CurrentUserContextTracker contextTracker, + UserContextProvider contextTracker, Provider<PriorityOnboardingDialogController.Builder> builderProvider, AssistantFeedbackController assistantFeedbackController, BubbleController bubbleController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 60074f608969..7d418f30e4c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -52,7 +52,7 @@ import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; @@ -121,7 +121,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx private final INotificationManager mNotificationManager; private final LauncherApps mLauncherApps; private final ShortcutManager mShortcutManager; - private final CurrentUserContextTracker mContextTracker; + private final UserContextProvider mContextTracker; private final Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider; private final UiEventLogger mUiEventLogger; @@ -138,7 +138,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx LauncherApps launcherApps, ShortcutManager shortcutManager, ChannelEditorDialogController channelEditorDialogController, - CurrentUserContextTracker contextTracker, + UserContextProvider contextTracker, Provider<PriorityOnboardingDialogController.Builder> builderProvider, AssistantFeedbackController assistantFeedbackController, BubbleController bubbleController, @@ -484,7 +484,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx onSettingsClick, onSnoozeClickListener, iconFactoryLoader, - mContextTracker.getCurrentUserContext(), + mContextTracker.getUserContext(), mBuilderProvider, mDeviceProvisionedController.isDeviceProvisioned(), mMainHandler, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index d5e55315ff0a..0302b2b450e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -81,17 +81,17 @@ public class AmbientState { private boolean mAppearing; private float mPulseHeight = MAX_PULSE_HEIGHT; private float mDozeAmount = 0.0f; - private HeadsUpManager mHeadUpManager; private Runnable mOnPulseHeightChangedListener; private ExpandableNotificationRow mTrackedHeadsUpRow; private float mAppearFraction; + /** Tracks the state from AlertingNotificationManager#hasNotifications() */ + private boolean mHasAlertEntries; + public AmbientState( Context context, - @NonNull SectionProvider sectionProvider, - HeadsUpManager headsUpManager) { + @NonNull SectionProvider sectionProvider) { mSectionProvider = sectionProvider; - mHeadUpManager = headsUpManager; reload(context); } @@ -393,7 +393,7 @@ public class AmbientState { } public boolean hasPulsingNotifications() { - return mPulsing && mHeadUpManager != null && mHeadUpManager.hasNotifications(); + return mPulsing && mHasAlertEntries; } public void setPulsing(boolean hasPulsing) { @@ -408,10 +408,7 @@ public class AmbientState { } public boolean isPulsing(NotificationEntry entry) { - if (!mPulsing || mHeadUpManager == null) { - return false; - } - return mHeadUpManager.isAlerting(entry.getKey()); + return mPulsing && entry.isAlerting(); } public boolean isPanelTracking() { @@ -568,4 +565,8 @@ public class AmbientState { public float getAppearFraction() { return mAppearFraction; } + + public void setHasAlertEntries(boolean hasAlertEntries) { + mHasAlertEntries = hasAlertEntries; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index b1a9efe40fdb..8a0fcf0d88f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -92,7 +92,6 @@ import com.android.systemui.Dumpable; import com.android.systemui.ExpandHelper; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.statusbar.CommandQueue; @@ -102,7 +101,6 @@ import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationShelfController; -import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; @@ -132,7 +130,6 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationSnooze; import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.HeadsUpTouchHelper; import com.android.systemui.statusbar.phone.LockscreenGestureLogger; import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; @@ -340,13 +337,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private HashSet<ExpandableView> mClearTransientViewsWhenFinished = new HashSet<>(); private HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations = new HashSet<>(); - private HeadsUpManagerPhone mHeadsUpManager; private final NotificationRoundnessManager mRoundnessManager; private boolean mTrackingHeadsUp; private ScrimController mScrimController; private boolean mForceNoOverlappingRendering; private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>(); - private FalsingManager mFalsingManager; private boolean mAnimationRunning; private ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater = new ViewTreeObserver.OnPreDrawListener() { @@ -513,6 +508,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private NotificationStackScrollLayoutController mController; private boolean mKeyguardMediaControllorVisible; + private NotificationEntry mTopHeadsUpEntry; + private long mNumHeadsUp; private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener = new ExpandableView.OnHeightChangedListener() { @@ -562,8 +559,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable NotificationRoundnessManager notificationRoundnessManager, DynamicPrivacyController dynamicPrivacyController, SysuiStatusBarStateController statusbarStateController, - HeadsUpManagerPhone headsUpManager, - FalsingManager falsingManager, NotificationGutsManager notificationGutsManager, NotificationSectionsManager notificationSectionsManager, ForegroundServiceSectionController fgsSectionController, @@ -580,9 +575,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mRoundnessManager = notificationRoundnessManager; mNotificationGutsManager = notificationGutsManager; - mHeadsUpManager = headsUpManager; - mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed); - mFalsingManager = falsingManager; mFgsSectionController = fgsSectionController; mSectionsManager = notificationSectionsManager; @@ -594,7 +586,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable }); mSections = mSectionsManager.createSectionsForBuckets(); - mAmbientState = new AmbientState(context, mSectionsManager, mHeadsUpManager); + mAmbientState = new AmbientState(context, mSectionsManager); mBgColor = context.getColor(R.color.notification_shade_background_color); int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height); int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height); @@ -750,27 +742,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable return false; } - @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public RemoteInputController.Delegate createDelegate() { - return new RemoteInputController.Delegate() { - public void setRemoteInputActive(NotificationEntry entry, - boolean remoteInputActive) { - mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive); - entry.notifyHeightChanged(true /* needsAnimation */); - updateFooter(); - } - - public void lockScrollTo(NotificationEntry entry) { - NotificationStackScrollLayout.this.lockScrollTo(entry.getRow()); - } - - public void requestDisallowLongPressAndDismiss() { - requestDisallowLongPress(); - requestDisallowDismiss(); - } - }; - } - @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public NotificationSwipeActionHelper getSwipeActionHelper() { return mSwipeHelper; @@ -1472,11 +1443,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable */ @ShadeViewRefactor(RefactorComponent.COORDINATOR) private int getTopHeadsUpPinnedHeight() { - NotificationEntry topEntry = mHeadsUpManager.getTopEntry(); - if (topEntry == null) { + if (mTopHeadsUpEntry == null) { return 0; } - ExpandableNotificationRow row = topEntry.getRow(); + ExpandableNotificationRow row = mTopHeadsUpEntry.getRow(); if (row.isChildInGroup()) { final NotificationEntry groupSummary = mGroupManager.getGroupSummary(row.getEntry().getSbn()); @@ -1497,7 +1467,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable int visibleNotifCount = getVisibleNotificationCount(); if (mEmptyShadeView.getVisibility() == GONE && visibleNotifCount > 0) { if (isHeadsUpTransition() - || (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDozing())) { + || (mInHeadsUpPinnedMode && !mAmbientState.isDozing())) { if (mShelf.getVisibility() != GONE && visibleNotifCount > 1) { appearPosition += mShelf.getIntrinsicHeight() + mPaddingBetweenElements; } @@ -1655,9 +1625,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild; NotificationEntry entry = row.getEntry(); if (!mIsExpanded && row.isHeadsUp() && row.isPinned() - && mHeadsUpManager.getTopEntry().getRow() != row + && mTopHeadsUpEntry.getRow() != row && mGroupManager.getGroupSummary( - mHeadsUpManager.getTopEntry().getSbn()) + mTopHeadsUpEntry.getSbn()) != entry) { continue; } @@ -2285,7 +2255,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable // In current design, it only use the top HUN to treat all of HUNs // although there are more than one HUNs int contentHeight = mContentHeight; - if (!isExpanded() && mHeadsUpManager.hasPinnedHeadsUp()) { + if (!isExpanded() && mInHeadsUpPinnedMode) { contentHeight = mHeadsUpInset + getTopHeadsUpPinnedHeight(); } int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight); @@ -2636,7 +2606,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable false /* shiftPulsingWithFirst */); minTopPosition = firstVisibleSection.getBounds().top; } - boolean shiftPulsingWithFirst = mHeadsUpManager.getAllEntries().count() <= 1 + boolean shiftPulsingWithFirst = mNumHeadsUp <= 1 && (mAmbientState.isDozing() || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard)); for (NotificationSection section : mSections) { @@ -3511,7 +3481,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable // Only animate if we still have pinned heads up, otherwise we just have the // regular collapse animation of the lock screen || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard() - && mHeadsUpManager.hasPinnedHeadsUp()); + && mInHeadsUpPinnedMode); if (performDisappearAnimation && !isHeadsUp) { type = row.wasJustClicked() ? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK @@ -5811,23 +5781,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mCurrentUserId = userId; } - void onMenuShown(View row) { - mSwipeHelper.onMenuShown(row); - } - - void onMenuReset(View row) { - View translatingParentView = mSwipeHelper.getTranslatingParentView(); - if (translatingParentView != null && row == translatingParentView) { - mSwipeHelper.clearExposedMenuView(); - mSwipeHelper.clearTranslatingParentView(); - if (row instanceof ExpandableNotificationRow) { - mHeadsUpManager.setMenuShown( - ((ExpandableNotificationRow) row).getEntry(), false); - - } - } - } - void addSwipedOutView(View v) { mSwipedOutViews.add(v); } @@ -5840,6 +5793,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mAmbientState.onDragFinished(view); } + void setTopHeadsUpEntry(NotificationEntry topEntry) { + mTopHeadsUpEntry = topEntry; + } + + void setNumHeadsUp(long numHeadsUp) { + mNumHeadsUp = numHeadsUp; + mAmbientState.setHasAlertEntries(numHeadsUp > 0); + } + /** * A listener that is notified when the empty space below the notifications is clicked on */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 73b4cad4ced5..b9fc5781def4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -70,6 +70,7 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.tuner.TunerService; @@ -110,6 +111,7 @@ public class NotificationStackScrollLayoutController { private NotificationStackScrollLayout mView; private boolean mFadeNotificationsOnDismiss; + private NotificationSwipeHelper mSwipeHelper; private final NotificationListContainerImpl mNotificationListContainer = new NotificationListContainerImpl(); @@ -217,7 +219,16 @@ public class NotificationStackScrollLayoutController { @Override public void onMenuReset(View row) { - mView.onMenuReset(row); + View translatingParentView = mSwipeHelper.getTranslatingParentView(); + if (translatingParentView != null && row == translatingParentView) { + mSwipeHelper.clearExposedMenuView(); + mSwipeHelper.clearTranslatingParentView(); + if (row instanceof ExpandableNotificationRow) { + mHeadsUpManager.setMenuShown( + ((ExpandableNotificationRow) row).getEntry(), false); + + } + } } @Override @@ -228,7 +239,7 @@ public class NotificationStackScrollLayoutController { .setCategory(MetricsEvent.ACTION_REVEAL_GEAR) .setType(MetricsEvent.TYPE_ACTION)); mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true); - mView.onMenuShown(row); + mSwipeHelper.onMenuShown(row); mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */); @@ -438,7 +449,31 @@ public class NotificationStackScrollLayoutController { } }; - private NotificationSwipeHelper mSwipeHelper; + private final OnHeadsUpChangedListener mOnHeadsUpChangedListener = + new OnHeadsUpChangedListener() { + @Override + public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) { + mView.setInHeadsUpPinnedMode(inPinnedMode); + } + + @Override + public void onHeadsUpPinned(NotificationEntry entry) { + + } + + @Override + public void onHeadsUpUnPinned(NotificationEntry entry) { + + } + + @Override + public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { + long numEntries = mHeadsUpManager.getAllEntries().count(); + NotificationEntry topEntry = mHeadsUpManager.getTopEntry(); + mView.setNumHeadsUp(numEntries); + mView.setTopHeadsUpEntry(topEntry); + } + }; @Inject public NotificationStackScrollLayoutController( @@ -496,6 +531,8 @@ public class NotificationStackScrollLayoutController { mSwipeHelper); mHeadsUpManager.addListener(mNotificationRoundnessManager); // TODO: why is this here? + mHeadsUpManager.addListener(mOnHeadsUpChangedListener); + mHeadsUpManager.setAnimationStateHandler(mView::setHeadsUpGoingAwayAnimationsAllowed); mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener); mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener); @@ -910,7 +947,23 @@ public class NotificationStackScrollLayoutController { } public RemoteInputController.Delegate createDelegate() { - return mView.createDelegate(); + return new RemoteInputController.Delegate() { + public void setRemoteInputActive(NotificationEntry entry, + boolean remoteInputActive) { + mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive); + entry.notifyHeightChanged(true /* needsAnimation */); + updateFooter(); + } + + public void lockScrollTo(NotificationEntry entry) { + mView.lockScrollTo(entry.getRow()); + } + + public void requestDisallowLongPressAndDismiss() { + mView.requestDisallowLongPress(); + mView.requestDisallowDismiss(); + } + }; } public void updateSectionBoundaries(String reason) { @@ -966,10 +1019,6 @@ public class NotificationStackScrollLayoutController { return mView.getFirstChildNotGone(); } - public void setInHeadsUpPinnedMode(boolean inPinnedMode) { - mView.setInHeadsUpPinnedMode(inPinnedMode); - } - public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) { mView.generateHeadsUpAnimation(entry, isHeadsUp); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 8750a02ed5b3..148029758a05 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -3546,7 +3546,6 @@ public class NotificationPanelViewController extends PanelViewController { private class MyOnHeadsUpChangedListener implements OnHeadsUpChangedListener { @Override public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) { - mNotificationStackScrollLayoutController.setInHeadsUpPinnedMode(inPinnedMode); if (inPinnedMode) { mHeadsUpExistenceChangedRunnable.run(); updateNotificationTranslucency(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java index c8e0f490a783..909acead9553 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java @@ -69,7 +69,7 @@ import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.GlobalActions; import com.android.systemui.plugins.GlobalActionsPanelPlugin; -import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -125,7 +125,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase { @Mock GlobalActionsPanelPlugin mWalletPlugin; @Mock GlobalActionsPanelPlugin.PanelViewController mWalletController; @Mock private Handler mHandler; - @Mock private CurrentUserContextTracker mCurrentUserContextTracker; + @Mock private UserContextProvider mUserContextProvider; private ControlsComponent mControlsComponent; private TestableLooper mTestableLooper; @@ -137,7 +137,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase { allowTestableLooperAsMainThread(); when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData); - when(mCurrentUserContextTracker.getCurrentUserContext()).thenReturn(mContext); + when(mUserContextProvider.getUserContext()).thenReturn(mContext); mControlsComponent = new ControlsComponent( true, () -> mControlsController, @@ -176,7 +176,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase { mSysUiState, mHandler, mControlsComponent, - mCurrentUserContextTracker + mUserContextProvider ); mGlobalActionsDialog.setZeroDialogPressDelayForTesting(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java index 4c9e141c45cc..3e37fde84544 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java @@ -33,7 +33,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import org.junit.Before; @@ -62,7 +62,7 @@ public class RecordingServiceTest extends SysuiTestCase { @Mock private Executor mExecutor; @Mock - private CurrentUserContextTracker mUserContextTracker; + private UserContextProvider mUserContextTracker; private KeyguardDismissUtil mKeyguardDismissUtil = new KeyguardDismissUtil() { public void executeWhenUnlocked(ActivityStarter.OnDismissAction action, boolean requiresShadeOpen) { @@ -92,7 +92,7 @@ public class RecordingServiceTest extends SysuiTestCase { doNothing().when(mRecordingService).startForeground(anyInt(), any()); doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder(); - doReturn(mContext).when(mUserContextTracker).getCurrentUserContext(); + doReturn(mContext).when(mUserContextTracker).getUserContext(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserContextTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserContextTrackerTest.kt deleted file mode 100644 index 628c06a56abd..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserContextTrackerTest.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.settings - -import android.content.Context -import android.content.ContextWrapper -import android.os.UserHandle -import android.testing.AndroidTestingRunner -import android.testing.TestableLooper -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.broadcast.BroadcastDispatcher -import junit.framework.Assert.assertTrue -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.Mockito.`when` -import org.mockito.Mockito.mock -import org.mockito.MockitoAnnotations - -@SmallTest -@RunWith(AndroidTestingRunner::class) -@TestableLooper.RunWithLooper -class CurrentUserContextTrackerTest : SysuiTestCase() { - - private lateinit var tracker: CurrentUserContextTracker - @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - allowTestableLooperAsMainThread() - - // wrap Context so that tests don't throw for missing package errors - val wrapped = object : ContextWrapper(context) { - override fun createContextAsUser(user: UserHandle, flags: Int): Context { - val mockContext = mock(Context::class.java) - `when`(mockContext.user).thenReturn(user) - `when`(mockContext.userId).thenReturn(user.identifier) - return mockContext - } - } - - tracker = CurrentUserContextTracker(wrapped, broadcastDispatcher) - tracker.initialize() - } - - @Test - fun testContextExistsAfterInit_noCrash() { - tracker.currentUserContext - } - - @Test - fun testUserContextIsCorrectAfterUserSwitch() { - // We always start out with system ui test - assertTrue("Starting userId should be 0", tracker.currentUserContext.userId == 0) - - // WHEN user changes - tracker.handleUserSwitched(1) - - // THEN user context should have the correct userId - assertTrue("User has changed to userId 1, the context should reflect that", - tracker.currentUserContext.userId == 1) - } - - @Suppress("UNUSED_PARAMETER") - @Test(expected = IllegalStateException::class) - fun testContextTrackerThrowsExceptionWhenNotInitialized() { - // GIVEN an uninitialized CurrentUserContextTracker - val userTracker = CurrentUserContextTracker(context, broadcastDispatcher) - - // WHEN client asks for a context - val userContext = userTracker.currentUserContext - - // THEN an exception is thrown - } -}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt new file mode 100644 index 000000000000..f76b50a173c3 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.settings + +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.pm.UserInfo +import android.os.Handler +import android.os.UserHandle +import android.os.UserManager +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.DumpManager +import com.android.systemui.util.mockito.capture +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.eq +import org.mockito.ArgumentMatchers.isNull +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import java.util.concurrent.Executor + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class UserTrackerImplTest : SysuiTestCase() { + + @Mock + private lateinit var context: Context + @Mock + private lateinit var userManager: UserManager + @Mock(stubOnly = true) + private lateinit var dumpManager: DumpManager + @Mock(stubOnly = true) + private lateinit var handler: Handler + + private val executor = Executor(Runnable::run) + private lateinit var tracker: UserTrackerImpl + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + `when`(context.userId).thenReturn(UserHandle.USER_SYSTEM) + `when`(context.user).thenReturn(UserHandle.SYSTEM) + `when`(context.createContextAsUser(any(), anyInt())).thenAnswer { invocation -> + val user = invocation.getArgument<UserHandle>(0) + `when`(context.user).thenReturn(user) + `when`(context.userId).thenReturn(user.identifier) + context + } + `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation -> + val info = UserInfo(invocation.getArgument<Int>(0), "", UserInfo.FLAG_FULL) + listOf(info) + } + + tracker = UserTrackerImpl(context, userManager, dumpManager, handler) + } + + @Test + fun testNotInitialized() { + assertThat(tracker.initialized).isFalse() + } + + @Test(expected = IllegalStateException::class) + fun testGetUserIdBeforeInitThrowsException() { + tracker.userId + } + + @Test(expected = IllegalStateException::class) + fun testGetUserHandleBeforeInitThrowsException() { + tracker.userHandle + } + + @Test(expected = IllegalStateException::class) + fun testGetUserContextBeforeInitThrowsException() { + tracker.userContext + } + + @Test(expected = IllegalStateException::class) + fun testGetUserContentResolverBeforeInitThrowsException() { + tracker.userContentResolver + } + + @Test(expected = IllegalStateException::class) + fun testGetUserProfilesBeforeInitThrowsException() { + tracker.userProfiles + } + + @Test + fun testInitialize() { + tracker.initialize(0) + + assertThat(tracker.initialized).isTrue() + } + + @Test + fun testReceiverRegisteredOnInitialize() { + tracker.initialize(0) + + val captor = ArgumentCaptor.forClass(IntentFilter::class.java) + + verify(context).registerReceiverForAllUsers( + eq(tracker), capture(captor), isNull(), eq(handler)) + } + + @Test + fun testInitialValuesSet() { + val testID = 4 + tracker.initialize(testID) + + verify(userManager).getProfiles(testID) + + assertThat(tracker.userId).isEqualTo(testID) + assertThat(tracker.userHandle).isEqualTo(UserHandle.of(testID)) + assertThat(tracker.userContext.userId).isEqualTo(testID) + assertThat(tracker.userContext.user).isEqualTo(UserHandle.of(testID)) + assertThat(tracker.userProfiles).hasSize(1) + + val info = tracker.userProfiles[0] + assertThat(info.id).isEqualTo(testID) + } + + @Test + fun testUserSwitch() { + tracker.initialize(0) + val newID = 5 + + val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, newID) + tracker.onReceive(context, intent) + + verify(userManager).getProfiles(newID) + + assertThat(tracker.userId).isEqualTo(newID) + assertThat(tracker.userHandle).isEqualTo(UserHandle.of(newID)) + assertThat(tracker.userContext.userId).isEqualTo(newID) + assertThat(tracker.userContext.user).isEqualTo(UserHandle.of(newID)) + assertThat(tracker.userProfiles).hasSize(1) + + val info = tracker.userProfiles[0] + assertThat(info.id).isEqualTo(newID) + } + + @Test + fun testManagedProfileAvailable() { + tracker.initialize(0) + val profileID = tracker.userId + 10 + + `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation -> + val id = invocation.getArgument<Int>(0) + val info = UserInfo(id, "", UserInfo.FLAG_FULL) + val infoProfile = UserInfo( + id + 10, + "", + "", + UserInfo.FLAG_MANAGED_PROFILE, + UserManager.USER_TYPE_PROFILE_MANAGED + ) + infoProfile.profileGroupId = id + listOf(info, infoProfile) + } + + val intent = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) + .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID)) + tracker.onReceive(context, intent) + + assertThat(tracker.userProfiles.map { it.id }).containsExactly(tracker.userId, profileID) + } + + @Test + fun testCallbackNotCalledOnAdd() { + tracker.initialize(0) + val callback = TestCallback() + + tracker.addCallback(callback, executor) + + assertThat(callback.calledOnProfilesChanged).isEqualTo(0) + assertThat(callback.calledOnUserChanged).isEqualTo(0) + } + + @Test + fun testCallbackCalledOnUserChanged() { + tracker.initialize(0) + val callback = TestCallback() + tracker.addCallback(callback, executor) + + val newID = 5 + + val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, newID) + tracker.onReceive(context, intent) + + assertThat(callback.calledOnUserChanged).isEqualTo(1) + assertThat(callback.lastUser).isEqualTo(newID) + assertThat(callback.lastUserContext?.userId).isEqualTo(newID) + assertThat(callback.calledOnProfilesChanged).isEqualTo(1) + assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(newID) + } + + @Test + fun testCallbackCalledOnProfileChanged() { + tracker.initialize(0) + val callback = TestCallback() + tracker.addCallback(callback, executor) + val profileID = tracker.userId + 10 + + `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation -> + val id = invocation.getArgument<Int>(0) + val info = UserInfo(id, "", UserInfo.FLAG_FULL) + val infoProfile = UserInfo( + id + 10, + "", + "", + UserInfo.FLAG_MANAGED_PROFILE, + UserManager.USER_TYPE_PROFILE_MANAGED + ) + infoProfile.profileGroupId = id + listOf(info, infoProfile) + } + + val intent = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) + .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID)) + + tracker.onReceive(context, intent) + + assertThat(callback.calledOnUserChanged).isEqualTo(0) + assertThat(callback.calledOnProfilesChanged).isEqualTo(1) + assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(0, profileID) + } + + @Test + fun testCallbackRemoved() { + tracker.initialize(0) + val newID = 5 + val profileID = newID + 10 + + val callback = TestCallback() + tracker.addCallback(callback, executor) + tracker.removeCallback(callback) + + val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, 5) + tracker.onReceive(context, intent) + + val intentProfiles = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) + .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID)) + + tracker.onReceive(context, intentProfiles) + + assertThat(callback.calledOnUserChanged).isEqualTo(0) + assertThat(callback.calledOnProfilesChanged).isEqualTo(0) + } + + private class TestCallback : UserTracker.Callback { + var calledOnUserChanged = 0 + var calledOnProfilesChanged = 0 + var lastUser: Int? = null + var lastUserContext: Context? = null + var lastUserProfiles = emptyList<UserInfo>() + + override fun onUserChanged(newUser: Int, userContext: Context) { + calledOnUserChanged++ + lastUser = newUser + lastUserContext = userContext + } + + override fun onProfilesChanged(profiles: List<UserInfo>) { + calledOnProfilesChanged++ + lastUserProfiles = profiles + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index c2c40cac3d0f..e1668cab3333 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -69,7 +69,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.SysuiTestCase; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; -import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.notification.AssistantFeedbackController; @@ -128,7 +128,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private ShortcutManager mShortcutManager; @Mock private ChannelEditorDialogController mChannelEditorDialogController; @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier; - @Mock private CurrentUserContextTracker mContextTracker; + @Mock private UserContextProvider mContextTracker; @Mock private BubbleController mBubbleController; @Mock(answer = Answers.RETURNS_SELF) private PriorityOnboardingDialogController.Builder mBuilder; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index fa9ea6b1ea10..beb0cc2809ae 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -122,7 +122,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private EmptyShadeView mEmptyShadeView; @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private RemoteInputController mRemoteInputController; - @Mock private NotificationIconAreaController mNotificationIconAreaController; @Mock private MetricsLogger mMetricsLogger; @Mock private NotificationRoundnessManager mNotificationRoundnessManager; @Mock private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider; @@ -203,8 +202,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mNotificationRoundnessManager, mock(DynamicPrivacyController.class), mStatusBarStateController, - mHeadsUpManager, - new FalsingManagerFake(), mock(NotificationGutsManager.class), mNotificationSectionsManager, mock(ForegroundServiceSectionController.class), diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index 71f1833854ce..534533f2fc97 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -1133,9 +1133,7 @@ public class LocationManagerService extends ILocationManager.Stub { return; } - String dumpFilter = args.length == 0 ? null : args[0]; - - ipw.println("Location Manager State:"); + ipw.print("Location Manager State:"); ipw.increaseIndent(); ipw.println("Elapsed Realtime: " + TimeUtils.formatDuration(SystemClock.elapsedRealtime())); @@ -1166,34 +1164,28 @@ public class LocationManagerService extends ILocationManager.Stub { ipw.println( "Location Controller Extra Package: " + mExtraLocationControllerPackage + (mExtraLocationControllerPackageEnabled ? " [enabled]" - : "[disabled]")); + : " [disabled]")); } } ipw.println("Location Providers:"); ipw.increaseIndent(); for (LocationProviderManager manager : mProviderManagers) { - if (dumpFilter == null || manager.getName().equals(dumpFilter)) { - manager.dump(fd, ipw, args); - } + manager.dump(fd, ipw, args); } ipw.decreaseIndent(); - if (dumpFilter == null || GPS_PROVIDER.equals(dumpFilter)) { - if (mGnssManagerService != null) { - ipw.println("GNSS Manager:"); - ipw.increaseIndent(); - mGnssManagerService.dump(fd, ipw, args); - ipw.decreaseIndent(); - } - } - - if (dumpFilter == null || "geofence".equals(dumpFilter)) { - ipw.println("Geofence Manager:"); + if (mGnssManagerService != null) { + ipw.println("GNSS Manager:"); ipw.increaseIndent(); - mGeofenceManager.dump(fd, ipw, args); + mGnssManagerService.dump(fd, ipw, args); ipw.decreaseIndent(); } + + ipw.println("Geofence Manager:"); + ipw.increaseIndent(); + mGeofenceManager.dump(fd, ipw, args); + ipw.decreaseIndent(); } private class LocalService extends LocationManagerInternal { diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java index 06105bfcc0f3..66245a279666 100644 --- a/services/core/java/com/android/server/location/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/LocationProviderManager.java @@ -84,7 +84,7 @@ import com.android.server.LocalServices; import com.android.server.PendingIntentUtils; import com.android.server.location.LocationPermissions.PermissionLevel; import com.android.server.location.listeners.ListenerMultiplexer; -import com.android.server.location.listeners.RemovableListenerRegistration; +import com.android.server.location.listeners.RemoteListenerRegistration; import com.android.server.location.util.AppForegroundHelper; import com.android.server.location.util.AppForegroundHelper.AppForegroundListener; import com.android.server.location.util.AppOpsHelper; @@ -154,15 +154,8 @@ class LocationProviderManager extends @Override public void deliverOnLocationChanged(Location location, - @Nullable Runnable onCompleteCallback) - throws RemoteException { - mListener.onLocationChanged(location, - onCompleteCallback == null ? null : new IRemoteCallback.Stub() { - @Override - public void sendResult(Bundle data) { - onCompleteCallback.run(); - } - }); + @Nullable Runnable onCompleteCallback) throws RemoteException { + mListener.onLocationChanged(location, SingleUseCallback.wrap(onCompleteCallback)); } @Override @@ -221,7 +214,7 @@ class LocationProviderManager extends } protected abstract class Registration extends - RemovableListenerRegistration<LocationRequest, LocationTransport> { + RemoteListenerRegistration<LocationRequest, LocationTransport> { @PermissionLevel protected final int mPermissionLevel; private final WorkSource mWorkSource; @@ -306,11 +299,12 @@ class LocationProviderManager extends } @Override - protected final void onInactive() { + protected final ListenerOperation<LocationTransport> onInactive() { onHighPowerUsageChanged(); if (!getRequest().getHideFromAppOps()) { mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey()); } + return null; } @Override @@ -826,6 +820,12 @@ class LocationProviderManager extends @GuardedBy("mLock") @Override protected void onProviderListenerRegister() { + try { + ((IBinder) getKey()).linkToDeath(this, 0); + } catch (RemoteException e) { + remove(); + } + mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs( SystemClock.elapsedRealtime()); @@ -837,12 +837,6 @@ class LocationProviderManager extends 0, this, FgThread.getHandler(), getWorkSource()); } - try { - ((IBinder) getKey()).linkToDeath(this, 0); - } catch (RemoteException e) { - remove(); - } - // start listening for provider enabled/disabled events addEnabledListener(this); @@ -1066,8 +1060,13 @@ class LocationProviderManager extends mUserInfoHelper.addListener(mUserChangedListener); mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener); - // initialize enabled state - onUserStarted(UserHandle.USER_ALL); + long identity = Binder.clearCallingIdentity(); + try { + // initialize enabled state + onUserStarted(UserHandle.USER_ALL); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -1077,10 +1076,15 @@ class LocationProviderManager extends mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener); // notify and remove all listeners - onUserStopped(UserHandle.USER_ALL); - removeRegistrationIf(key -> true); - mEnabledListeners.clear(); + long identity = Binder.clearCallingIdentity(); + try { + onUserStopped(UserHandle.USER_ALL); + removeRegistrationIf(key -> true); + } finally { + Binder.restoreCallingIdentity(identity); + } + mEnabledListeners.clear(); mStarted = false; } } @@ -1141,14 +1145,26 @@ class LocationProviderManager extends public void setRealProvider(AbstractLocationProvider provider) { synchronized (mLock) { Preconditions.checkState(mStarted); - mProvider.setRealProvider(provider); + + long identity = Binder.clearCallingIdentity(); + try { + mProvider.setRealProvider(provider); + } finally { + Binder.restoreCallingIdentity(identity); + } } } public void setMockProvider(@Nullable MockProvider provider) { synchronized (mLock) { Preconditions.checkState(mStarted); - mProvider.setMockProvider(provider); + + long identity = Binder.clearCallingIdentity(); + try { + mProvider.setMockProvider(provider); + } finally { + Binder.restoreCallingIdentity(identity); + } // when removing a mock provider, also clear any mock last locations and reset the // location fudger. the mock provider could have been used to infer the current @@ -1170,7 +1186,12 @@ class LocationProviderManager extends throw new IllegalArgumentException(mName + " provider is not a test provider"); } - mProvider.setMockProviderAllowed(enabled); + long identity = Binder.clearCallingIdentity(); + try { + mProvider.setMockProviderAllowed(enabled); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -1180,15 +1201,20 @@ class LocationProviderManager extends throw new IllegalArgumentException(mName + " provider is not a test provider"); } - String locationProvider = location.getProvider(); - if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) { - // The location has an explicit provider that is different from the mock - // provider name. The caller may be trying to fool us via b/33091107. - EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(), - mName + "!=" + locationProvider); - } + long identity = Binder.clearCallingIdentity(); + try { + String locationProvider = location.getProvider(); + if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) { + // The location has an explicit provider that is different from the mock + // provider name. The caller may be trying to fool us via b/33091107. + EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(), + mName + "!=" + locationProvider); + } - mProvider.setMockProviderLocation(location); + mProvider.setMockProviderLocation(location); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -1279,7 +1305,7 @@ class LocationProviderManager extends } } - public void getCurrentLocation(LocationRequest request, CallerIdentity identity, + public void getCurrentLocation(LocationRequest request, CallerIdentity callerIdentity, int permissionLevel, ICancellationSignal cancellationTransport, ILocationCallback callback) { Preconditions.checkArgument(mName.equals(request.getProvider())); @@ -1291,12 +1317,12 @@ class LocationProviderManager extends GetCurrentLocationListenerRegistration registration = new GetCurrentLocationListenerRegistration( request, - identity, + callerIdentity, new GetCurrentLocationTransport(callback), permissionLevel); synchronized (mLock) { - Location lastLocation = getLastLocation(request, identity, permissionLevel); + Location lastLocation = getLastLocation(request, callerIdentity, permissionLevel); if (lastLocation != null) { long locationAgeMs = NANOSECONDS.toMillis( SystemClock.elapsedRealtimeNanos() @@ -1314,7 +1340,13 @@ class LocationProviderManager extends } // if last location isn't good enough then we add a location request - addRegistration(callback.asBinder(), registration); + long identity = Binder.clearCallingIdentity(); + try { + addRegistration(callback.asBinder(), registration); + } finally { + Binder.restoreCallingIdentity(identity); + } + CancellationSignal cancellationSignal = CancellationSignal.fromTransport( cancellationTransport); if (cancellationSignal != null) { @@ -1329,48 +1361,73 @@ class LocationProviderManager extends } public void sendExtraCommand(int uid, int pid, String command, Bundle extras) { - mProvider.sendExtraCommand(uid, pid, command, extras); + long identity = Binder.clearCallingIdentity(); + try { + mProvider.sendExtraCommand(uid, pid, command, extras); + } finally { + Binder.restoreCallingIdentity(identity); + } } - public void registerLocationRequest(LocationRequest request, CallerIdentity identity, + public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity, @PermissionLevel int permissionLevel, ILocationListener listener) { Preconditions.checkArgument(mName.equals(request.getProvider())); synchronized (mLock) { - addRegistration( - listener.asBinder(), - new LocationListenerRegistration( - request, - identity, - new LocationListenerTransport(listener), - permissionLevel)); + long identity = Binder.clearCallingIdentity(); + try { + addRegistration( + listener.asBinder(), + new LocationListenerRegistration( + request, + callerIdentity, + new LocationListenerTransport(listener), + permissionLevel)); + } finally { + Binder.restoreCallingIdentity(identity); + } } } - public void registerLocationRequest(LocationRequest request, CallerIdentity identity, + public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity, @PermissionLevel int permissionLevel, PendingIntent pendingIntent) { Preconditions.checkArgument(mName.equals(request.getProvider())); synchronized (mLock) { - addRegistration( - pendingIntent, - new LocationPendingIntentRegistration( - request, - identity, - new LocationPendingIntentTransport(mContext, pendingIntent), - permissionLevel)); + long identity = Binder.clearCallingIdentity(); + try { + addRegistration( + pendingIntent, + new LocationPendingIntentRegistration( + request, + callerIdentity, + new LocationPendingIntentTransport(mContext, pendingIntent), + permissionLevel)); + } finally { + Binder.restoreCallingIdentity(identity); + } } } public void unregisterLocationRequest(ILocationListener listener) { synchronized (mLock) { - removeRegistration(listener.asBinder()); + long identity = Binder.clearCallingIdentity(); + try { + removeRegistration(listener.asBinder()); + } finally { + Binder.restoreCallingIdentity(identity); + } } } public void unregisterLocationRequest(PendingIntent pendingIntent) { synchronized (mLock) { - removeRegistration(pendingIntent); + long identity = Binder.clearCallingIdentity(); + try { + removeRegistration(pendingIntent); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -1958,4 +2015,50 @@ class LocationProviderManager extends } } } + + private static class SingleUseCallback extends IRemoteCallback.Stub { + + @Nullable + public static IRemoteCallback wrap(@Nullable Runnable callback) { + return callback == null ? null : new SingleUseCallback(callback); + } + + @GuardedBy("this") + @Nullable private Runnable mCallback; + + private SingleUseCallback(Runnable callback) { + mCallback = Objects.requireNonNull(callback); + } + + @Override + public void sendResult(Bundle data) { + Runnable callback; + synchronized (this) { + callback = mCallback; + mCallback = null; + } + + // prevent this callback from being run more than once - otherwise this could provide an + // attack vector for a malicious app to break assumptions on how many times a callback + // may be invoked, and thus crash system server. + if (callback == null) { + return; + } + + long identity = Binder.clearCallingIdentity(); + try { + callback.run(); + } catch (RuntimeException e) { + // since this is within a oneway binder transaction there is nowhere + // for exceptions to go - move onto another thread to crash system + // server so we find out about it + FgThread.getExecutor().execute(() -> { + throw new AssertionError(e); + }); + throw e; + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } } diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java index 2d9734ef0553..2d7f02873b8f 100644 --- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java +++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java @@ -32,6 +32,7 @@ import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationRequest; import android.location.util.identity.CallerIdentity; +import android.os.Binder; import android.os.PowerManager; import android.os.SystemClock; import android.os.WorkSource; @@ -291,17 +292,28 @@ public class GeofenceManager extends @Nullable String attributionTag) { LocationPermissions.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_FINE); - CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, - AppOpsManager.toReceiverId(pendingIntent)); - addRegistration(new GeofenceKey(pendingIntent, geofence), - new GeofenceRegistration(geofence, identity, pendingIntent)); + CallerIdentity callerIdentity = CallerIdentity.fromBinder(mContext, packageName, + attributionTag, AppOpsManager.toReceiverId(pendingIntent)); + + long identity = Binder.clearCallingIdentity(); + try { + addRegistration(new GeofenceKey(pendingIntent, geofence), + new GeofenceRegistration(geofence, callerIdentity, pendingIntent)); + } finally { + Binder.restoreCallingIdentity(identity); + } } /** * Removes the geofence associated with the PendingIntent. */ public void removeGeofence(PendingIntent pendingIntent) { - removeRegistrationIf(key -> key.getPendingIntent().equals(pendingIntent)); + long identity = Binder.clearCallingIdentity(); + try { + removeRegistrationIf(key -> key.getPendingIntent().equals(pendingIntent)); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java index 1b599b026c38..a9fdacca9a06 100644 --- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java +++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java @@ -25,6 +25,7 @@ import android.annotation.Nullable; import android.location.LocationManagerInternal; import android.location.LocationManagerInternal.ProviderEnabledListener; import android.location.util.identity.CallerIdentity; +import android.os.Binder; import android.os.IBinder; import android.os.IInterface; import android.os.Process; @@ -218,16 +219,27 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter /** * Adds a listener with the given identity and request. */ - protected void addListener(TRequest request, CallerIdentity identity, TListener listener) { - addRegistration(listener.asBinder(), - new GnssListenerRegistration(request, identity, listener)); + protected void addListener(TRequest request, CallerIdentity callerIdentity, + TListener listener) { + long identity = Binder.clearCallingIdentity(); + try { + addRegistration(listener.asBinder(), + new GnssListenerRegistration(request, callerIdentity, listener)); + } finally { + Binder.restoreCallingIdentity(identity); + } } /** * Removes the given listener. */ public void removeListener(TListener listener) { - removeRegistration(listener.asBinder()); + long identity = Binder.clearCallingIdentity(); + try { + removeRegistration(listener.asBinder()); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index 850cf7f4b7ce..5c30fe840073 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -2022,6 +2022,21 @@ public class GnssLocationProvider extends AbstractLocationProvider implements @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + boolean dumpAll = false; + + int opti = 0; + while (opti < args.length) { + String opt = args[opti]; + if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { + break; + } + opti++; + if ("-a".equals(opt)) { + dumpAll = true; + break; + } + } + StringBuilder s = new StringBuilder(); s.append("mStarted=").append(mStarted).append(" (changed "); TimeUtils.formatDuration(SystemClock.elapsedRealtime() @@ -2053,9 +2068,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements s.append("]\n"); } s.append(mGnssMetrics.dumpGnssMetricsAsText()); - s.append("native internal state: \n"); - s.append(" ").append(native_get_internal_state()); - s.append("\n"); + if (dumpAll) { + s.append("native internal state: \n"); + s.append(" ").append(native_get_internal_state()); + s.append("\n"); + } pw.append(s); } diff --git a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java index bd8bce8f6d52..58aabdad056f 100644 --- a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java +++ b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java @@ -32,10 +32,10 @@ import android.util.Log; * @param <TListener> listener type */ public abstract class BinderListenerRegistration<TRequest, TListener> extends - RemovableListenerRegistration<TRequest, TListener> implements Binder.DeathRecipient { + RemoteListenerRegistration<TRequest, TListener> implements Binder.DeathRecipient { /** - * Interface to allowed binder retrieval when keys are not themselves IBinder. + * Interface to allow binder retrieval when keys are not themselves IBinders. */ public interface BinderKey { /** diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java index f94de9be0cfe..8a6b8aa1e463 100644 --- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java +++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java @@ -18,12 +18,9 @@ package com.android.server.location.listeners; import android.annotation.NonNull; import android.annotation.Nullable; -import android.os.Binder; import android.os.Build; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.IndentingPrintWriter; -import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.listeners.ListenerExecutor.ListenerOperation; @@ -31,8 +28,10 @@ import com.android.internal.util.Preconditions; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; +import java.util.Map.Entry; import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; @@ -42,7 +41,7 @@ import java.util.function.Predicate; * divided into two categories, active registrations and inactive registrations, as defined by * {@link #isActive(ListenerRegistration)}. If a registration's active state changes, * {@link #updateRegistrations(Predicate)} must be invoked and return true for any registration - * whose active state may have changed. + * whose active state may have changed. Listeners will only be invoked for active registrations. * * Callbacks invoked for various changes will always be ordered according to this lifecycle list: * @@ -64,14 +63,6 @@ import java.util.function.Predicate; * {@link #removeRegistration(Object, ListenerRegistration)}, not via any other removal method. This * ensures re-entrant removal does not accidentally remove the incorrect registration. * - * All callbacks will be invoked with a cleared binder identity. - * - * Listeners owned by other processes will be run on a direct executor (and thus while holding a - * lock). Listeners owned by the same process this multiplexer is in will be run asynchronously (and - * thus without holding a lock). The underlying assumption is that listeners owned by other - * processes will simply be forwarding the call to those other processes and perhaps performing - * simple bookkeeping, with no potential for deadlock. - * * @param <TKey> key type * @param <TRequest> request type * @param <TListener> listener type @@ -149,46 +140,51 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, } /** - * Invoked before the first registration occurs. This is a convenient entry point for - * registering listeners, etc, which only need to be present while there are any registrations. + * Invoked when the multiplexer goes from having no registrations to having some registrations. + * This is a convenient entry point for registering listeners, etc, which only need to be + * present while there are any registrations. Invoked while holding the multiplexer's internal + * lock. */ protected void onRegister() {} /** - * Invoked after the last unregistration occurs. This is a convenient entry point for - * unregistering listeners, etc, which only need to be present while there are any - * registrations. + * Invoked when the multiplexer goes from having some registrations to having no registrations. + * This is a convenient entry point for unregistering listeners, etc, which only need to be + * present while there are any registrations. Invoked while holding the multiplexer's internal + * lock. */ protected void onUnregister() {} /** - * Invoked when a registration is added. + * Invoked when a registration is added. Invoked while holding the multiplexer's internal lock. */ protected void onRegistrationAdded(@NonNull TKey key, @NonNull TRegistration registration) {} /** - * Invoked when a registration is removed. + * Invoked when a registration is removed. Invoked while holding the multiplexer's internal + * lock. */ protected void onRegistrationRemoved(@NonNull TKey key, @NonNull TRegistration registration) {} /** - * Invoked when the manager goes from having no active registrations to having some active + * Invoked when the multiplexer goes from having no active registrations to having some active * registrations. This is a convenient entry point for registering listeners, etc, which only - * need to be present while there are active registrations. + * need to be present while there are active registrations. Invoked while holding the + * multiplexer's internal lock. */ protected void onActive() {} /** - * Invoked when the manager goes from having some active registrations to having no active + * Invoked when the multiplexer goes from having some active registrations to having no active * registrations. This is a convenient entry point for unregistering listeners, etc, which only - * need to be present while there are active registrations. + * need to be present while there are active registrations. Invoked while holding the + * multiplexer's internal lock. */ protected void onInactive() {} /** - * Adds a new registration with the given key. Registration may fail if - * {@link ListenerRegistration#onRegister(Object)} returns false, in which case the registration - * will not be added. This method cannot be called to add a registration re-entrantly. + * Adds a new registration with the given key. This method cannot be called to add a + * registration re-entrantly. */ protected final void addRegistration(@NonNull TKey key, @NonNull TRegistration registration) { Objects.requireNonNull(key); @@ -204,7 +200,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, // involve removing a prior registration. note that try-with-resources ordering is // meaningful here as well. we want to close the reentrancy guard first, as this may // generate additional service updates, then close the update service buffer. - long identity = Binder.clearCallingIdentity(); try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire(); ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) { @@ -224,16 +219,13 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, registration.onRegister(key); onRegistrationAdded(key, registration); onRegistrationActiveChanged(registration); - } finally { - Binder.restoreCallingIdentity(identity); } } } /** - * Removes the registration with the given key. If unregistration occurs, - * {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This method - * cannot be called to remove a registration re-entrantly. + * Removes the registration with the given key. This method cannot be called to remove a + * registration re-entrantly. */ protected final void removeRegistration(@NonNull Object key) { synchronized (mRegistrations) { @@ -250,9 +242,8 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, } /** - * Removes all registrations with keys that satisfy the given predicate. If unregistration - * occurs, {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This - * method cannot be called to remove a registration re-entrantly. + * Removes all registrations with keys that satisfy the given predicate. This method cannot be + * called to remove a registration re-entrantly. */ protected final void removeRegistrationIf(@NonNull Predicate<TKey> predicate) { synchronized (mRegistrations) { @@ -281,11 +272,8 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, /** * Removes the given registration with the given key. If the given key has a different - * registration at the time this method is called, nothing happens. If unregistration occurs, - * {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This method - * allows for re-entrancy, and may be called to remove a registration re-entrantly. In this case - * the registration will immediately be marked inactive and unregistered, and will be removed - * completely at some later time. + * registration at the time this method is called, nothing happens. This method allows for + * re-entrancy, and may be called to remove a registration re-entrantly. */ protected final void removeRegistration(@NonNull Object key, @NonNull ListenerRegistration<?, ?> registration) { @@ -324,7 +312,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, // in multiple service updates. note that try-with-resources ordering is meaningful here as // well. we want to close the reentrancy guard first, as this may generate additional // service updates, then close the update service buffer. - long identity = Binder.clearCallingIdentity(); try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire(); ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) { @@ -337,8 +324,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, onUnregister(); } } - } finally { - Binder.restoreCallingIdentity(identity); } } @@ -362,38 +347,46 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, } } - long identity = Binder.clearCallingIdentity(); - try { - if (actives.isEmpty()) { + if (actives.isEmpty()) { + mCurrentRequest = null; + if (mServiceRegistered) { + mServiceRegistered = false; mCurrentRequest = null; - if (mServiceRegistered) { - mServiceRegistered = false; - mCurrentRequest = null; - unregisterWithService(); - } - return; + unregisterWithService(); } + return; + } - TMergedRequest merged = mergeRequests(actives); - if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) { - if (mServiceRegistered) { - mServiceRegistered = reregisterWithService(mCurrentRequest, merged); - } else { - mServiceRegistered = registerWithService(merged); - } - if (mServiceRegistered) { - mCurrentRequest = merged; - } else { - mCurrentRequest = null; - } + TMergedRequest merged = mergeRequests(actives); + if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) { + if (mServiceRegistered) { + mServiceRegistered = reregisterWithService(mCurrentRequest, merged); + } else { + mServiceRegistered = registerWithService(merged); + } + if (mServiceRegistered) { + mCurrentRequest = merged; + } else { + mCurrentRequest = null; } - } finally { - Binder.restoreCallingIdentity(identity); } } } /** + * Clears currently stored service state, and invokes {@link #updateService()} to force a new + * call to {@link #registerWithService(Object)} if necessary. This is useful, for instance, if + * the backing service has crashed or otherwise lost state, and needs to be re-initialized. + */ + protected final void resetService() { + synchronized (mRegistrations) { + mServiceRegistered = false; + mCurrentRequest = null; + updateService(); + } + } + + /** * Begins buffering calls to {@link #updateService()} until {@link UpdateServiceLock#close()} * is called. This is useful to prevent extra work when combining multiple calls (for example, * buffering {@code updateService()} until after multiple adds/removes/updates occur. @@ -404,9 +397,9 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, /** * Evaluates the predicate on all registrations. The predicate should return true if the active - * state of the registration may have changed as a result. Any {@link #updateService()} - * invocations made while this method is executing will be deferred until after the method is - * complete so as to avoid redundant work. + * state of the registration may have changed as a result. If the active state of any + * registration has changed, {@link #updateService()} will automatically be invoked to handle + * the resulting changes. */ protected final void updateRegistrations(@NonNull Predicate<TRegistration> predicate) { synchronized (mRegistrations) { @@ -415,7 +408,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, // callbacks. note that try-with-resources ordering is meaningful here as well. we want // to close the reentrancy guard first, as this may generate additional service updates, // then close the update service buffer. - long identity = Binder.clearCallingIdentity(); try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire(); ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) { @@ -426,8 +418,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, onRegistrationActiveChanged(registration); } } - } finally { - Binder.restoreCallingIdentity(identity); } } } @@ -450,7 +440,10 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, execute(registration, operation); } } else { - registration.onInactive(); + ListenerOperation<TListener> operation = registration.onInactive(); + if (operation != null) { + execute(registration, operation); + } if (--mActiveRegistrationsCount == 0) { onInactive(); } @@ -468,7 +461,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, protected final void deliverToListeners( @NonNull Function<TRegistration, ListenerOperation<TListener>> function) { synchronized (mRegistrations) { - long identity = Binder.clearCallingIdentity(); try (ReentrancyGuard ignored = mReentrancyGuard.acquire()) { final int size = mRegistrations.size(); for (int i = 0; i < size; i++) { @@ -480,8 +472,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, } } } - } finally { - Binder.restoreCallingIdentity(identity); } } } @@ -495,7 +485,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, */ protected final void deliverToListeners(@NonNull ListenerOperation<TListener> operation) { synchronized (mRegistrations) { - long identity = Binder.clearCallingIdentity(); try (ReentrancyGuard ignored = mReentrancyGuard.acquire()) { final int size = mRegistrations.size(); for (int i = 0; i < size; i++) { @@ -504,8 +493,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, execute(registration, operation); } } - } finally { - Binder.restoreCallingIdentity(identity); } } } @@ -522,27 +509,26 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, /** * Dumps debug information. */ - public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) { + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { synchronized (mRegistrations) { - ipw.print("service: "); - dumpServiceState(ipw); - ipw.println(); + pw.print("service: "); + dumpServiceState(pw); + pw.println(); if (!mRegistrations.isEmpty()) { - ipw.println("listeners:"); + pw.println("listeners:"); - ipw.increaseIndent(); final int size = mRegistrations.size(); for (int i = 0; i < size; i++) { TRegistration registration = mRegistrations.valueAt(i); - ipw.print(registration); + pw.print(" "); + pw.print(registration); if (!registration.isActive()) { - ipw.println(" (inactive)"); + pw.println(" (inactive)"); } else { - ipw.println(); + pw.println(); } } - ipw.decreaseIndent(); } } } @@ -577,7 +563,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, @GuardedBy("mRegistrations") private int mGuardCount; @GuardedBy("mRegistrations") - private @Nullable ArraySet<Pair<Object, ListenerRegistration<?, ?>>> mScheduledRemovals; + private @Nullable ArraySet<Entry<Object, ListenerRegistration<?, ?>>> mScheduledRemovals; ReentrancyGuard() { mGuardCount = 0; @@ -602,7 +588,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, if (mScheduledRemovals == null) { mScheduledRemovals = new ArraySet<>(mRegistrations.size()); } - mScheduledRemovals.add(new Pair<>(key, registration)); + mScheduledRemovals.add(new AbstractMap.SimpleImmutableEntry<>(key, registration)); } ReentrancyGuard acquire() { @@ -612,7 +598,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, @Override public void close() { - ArraySet<Pair<Object, ListenerRegistration<?, ?>>> scheduledRemovals = null; + ArraySet<Entry<Object, ListenerRegistration<?, ?>>> scheduledRemovals = null; Preconditions.checkState(mGuardCount > 0); if (--mGuardCount == 0) { @@ -620,14 +606,15 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener, mScheduledRemovals = null; } - if (scheduledRemovals != null) { - try (UpdateServiceBuffer ignored = mUpdateServiceBuffer.acquire()) { - final int size = scheduledRemovals.size(); - for (int i = 0; i < size; i++) { - Pair<Object, ListenerRegistration<?, ?>> pair = scheduledRemovals.valueAt( - i); - removeRegistration(pair.first, pair.second); - } + if (scheduledRemovals == null) { + return; + } + + try (UpdateServiceBuffer ignored = mUpdateServiceBuffer.acquire()) { + final int size = scheduledRemovals.size(); + for (int i = 0; i < size; i++) { + Entry<Object, ListenerRegistration<?, ?>> entry = scheduledRemovals.valueAt(i); + removeRegistration(entry.getKey(), entry.getValue()); } } } diff --git a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java index ac56c51568be..deb9660a1c82 100644 --- a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java +++ b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java @@ -17,55 +17,34 @@ package com.android.server.location.listeners; -import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; - import android.annotation.NonNull; import android.annotation.Nullable; -import android.location.util.identity.CallerIdentity; -import android.os.Process; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.listeners.ListenerExecutor; -import com.android.server.FgThread; import java.util.Objects; import java.util.concurrent.Executor; /** * A listener registration object which holds data associated with the listener, such as an optional - * request, and the identity of the listener owner. + * request, and an executor responsible for listener invocations. * * @param <TRequest> request type * @param <TListener> listener type */ public class ListenerRegistration<TRequest, TListener> implements ListenerExecutor { - @VisibleForTesting - public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor(); - private final Executor mExecutor; private final @Nullable TRequest mRequest; - private final CallerIdentity mIdentity; private boolean mActive; private volatile @Nullable TListener mListener; - protected ListenerRegistration(@Nullable TRequest request, CallerIdentity identity, + protected ListenerRegistration(Executor executor, @Nullable TRequest request, TListener listener) { - // if a client is in the same process as us, binder calls will execute synchronously and - // we shouldn't run callbacks directly since they might be run under lock and deadlock - if (identity.getPid() == Process.myPid()) { - // there's a slight loophole here for pending intents - pending intent callbacks can - // always be run on the direct executor since they're always asynchronous, but honestly - // you shouldn't be using pending intent callbacks within the same process anyways - mExecutor = IN_PROCESS_EXECUTOR; - } else { - mExecutor = DIRECT_EXECUTOR; - } - + mExecutor = Objects.requireNonNull(executor); mRequest = request; - mIdentity = Objects.requireNonNull(identity); mActive = false; mListener = Objects.requireNonNull(listener); } @@ -82,34 +61,34 @@ public class ListenerRegistration<TRequest, TListener> implements ListenerExecut } /** - * Returns the listener identity. - */ - public final CallerIdentity getIdentity() { - return mIdentity; - } - - /** - * May be overridden by subclasses. Invoked when registration occurs. + * May be overridden by subclasses. Invoked when registration occurs. Invoked while holding the + * owning multiplexer's internal lock. */ protected void onRegister(Object key) {} /** - * May be overridden by subclasses. Invoked when unregistration occurs. + * May be overridden by subclasses. Invoked when unregistration occurs. Invoked while holding + * the owning multiplexer's internal lock. */ protected void onUnregister() {} /** * May be overridden by subclasses. Invoked when this registration becomes active. If this - * returns a non-null operation, that operation will be invoked for the listener. + * returns a non-null operation, that operation will be invoked for the listener. Invoked + * while holding the owning multiplexer's internal lock. */ protected @Nullable ListenerOperation<TListener> onActive() { return null; } /** - * May be overridden by subclasses. Invoked when registration becomes inactive. + * May be overridden by subclasses. Invoked when registration becomes inactive. If this returns + * a non-null operation, that operation will be invoked for the listener. Invoked while holding + * the owning multiplexer's internal lock. */ - protected void onInactive() {} + protected @Nullable ListenerOperation<TListener> onInactive() { + return null; + } public final boolean isActive() { return mActive; @@ -136,8 +115,7 @@ public class ListenerRegistration<TRequest, TListener> implements ListenerExecut /** * May be overridden by subclasses, however should rarely be needed. Invoked when the listener * associated with this registration is unregistered, which may occur before the registration - * itself is unregistered. This immediately prevents the listener from being further invoked - * even if the various bookkeeping associated with unregistration has not occurred yet. + * itself is unregistered. This immediately prevents the listener from being further invoked. */ protected void onListenerUnregister() {}; diff --git a/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java b/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java index b5d2ef6a72ec..7b6154eb0d00 100644 --- a/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java +++ b/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java @@ -30,7 +30,7 @@ import android.util.Log; * @param <TListener> listener type */ public abstract class PendingIntentListenerRegistration<TRequest, TListener> extends - RemovableListenerRegistration<TRequest, TListener> implements PendingIntent.CancelListener { + RemoteListenerRegistration<TRequest, TListener> implements PendingIntent.CancelListener { /** * Interface to allowed pending intent retrieval when keys are not themselves PendingIntents. diff --git a/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java new file mode 100644 index 000000000000..e4b0b190d34c --- /dev/null +++ b/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location.listeners; + + +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; + +import android.annotation.Nullable; +import android.location.util.identity.CallerIdentity; +import android.os.Process; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.FgThread; + +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * A listener registration representing a remote (possibly from a different process) listener. + * Listeners from a different process will be run on a direct executor, since the x-process listener + * invocation should already be asynchronous. Listeners from the same process will be run on a + * normal executor, since in-process listener invocation may be synchronous. + * + * @param <TRequest> request type + * @param <TListener> listener type + */ +public abstract class RemoteListenerRegistration<TRequest, TListener> extends + RemovableListenerRegistration<TRequest, TListener> { + + @VisibleForTesting + public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor(); + + private static Executor chooseExecutor(CallerIdentity identity) { + // if a client is in the same process as us, binder calls will execute synchronously and + // we shouldn't run callbacks directly since they might be run under lock and deadlock + if (identity.getPid() == Process.myPid()) { + // there's a slight loophole here for pending intents - pending intent callbacks can + // always be run on the direct executor since they're always asynchronous, but honestly + // you shouldn't be using pending intent callbacks within the same process anyways + return IN_PROCESS_EXECUTOR; + } else { + return DIRECT_EXECUTOR; + } + } + + private final CallerIdentity mIdentity; + + protected RemoteListenerRegistration(String tag, @Nullable TRequest request, + CallerIdentity identity, TListener listener) { + super(tag, chooseExecutor(identity), request, listener); + mIdentity = Objects.requireNonNull(identity); + } + + /** + * Returns the listener identity. + */ + public final CallerIdentity getIdentity() { + return mIdentity; + } +} + diff --git a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java index 0698cca903f0..2383bece4e0a 100644 --- a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java +++ b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java @@ -17,10 +17,10 @@ package com.android.server.location.listeners; import android.annotation.Nullable; -import android.location.util.identity.CallerIdentity; import android.util.Log; import java.util.Objects; +import java.util.concurrent.Executor; /** * A listener registration that stores its own key, and thus can remove itself. By default it will @@ -36,9 +36,9 @@ public abstract class RemovableListenerRegistration<TRequest, TListener> extends private volatile @Nullable Object mKey; - protected RemovableListenerRegistration(String tag, @Nullable TRequest request, - CallerIdentity callerIdentity, TListener listener) { - super(request, callerIdentity, listener); + protected RemovableListenerRegistration(String tag, Executor executor, + @Nullable TRequest request, TListener listener) { + super(executor, request, listener); mTag = Objects.requireNonNull(tag); } @@ -70,7 +70,7 @@ public abstract class RemovableListenerRegistration<TRequest, TListener> extends @Override public <Listener> void onOperationFailure(ListenerOperation<Listener> operation, Exception e) { - Log.w(mTag, "registration " + getIdentity() + " removed due to unexpected exception", e); + Log.w(mTag, "registration " + this + " removed due to unexpected exception", e); remove(); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bb7b63bbc933..c488a1716219 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -11671,7 +11671,7 @@ public class PackageManagerService extends IPackageManager.Stub configurePackageComponents(parsedPackage); } - final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride, pkgSetting); + final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride); final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp(); if ((scanFlags & SCAN_NEW_INSTALL) == 0) { @@ -17704,7 +17704,7 @@ public class PackageManagerService extends IPackageManager.Stub } boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null && pkgSetting.getPkgState().isUpdatedSystemApp(); - final String abiOverride = deriveAbiOverride(args.abiOverride, pkgSetting); + final String abiOverride = deriveAbiOverride(args.abiOverride); AndroidPackage oldPackage = mPackages.get(pkgName); boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem(); final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 491b4fc515ce..5553cd0e2fb8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -421,18 +421,13 @@ public class PackageManagerServiceUtils { /** * Derive the value of the {@code cpuAbiOverride} based on the provided - * value and an optional stored value from the package settings. + * value. */ - public static String deriveAbiOverride(String abiOverride, PackageSetting settings) { - String cpuAbiOverride = null; + public static String deriveAbiOverride(String abiOverride) { if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) { - cpuAbiOverride = null; - } else if (abiOverride != null) { - cpuAbiOverride = abiOverride; - } else if (settings != null) { - cpuAbiOverride = settings.cpuAbiOverrideString; + return null; } - return cpuAbiOverride; + return abiOverride; } /** diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 137c587b1d79..d01a30fbd818 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -69,6 +69,7 @@ import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION; import static android.view.WindowManagerGlobal.ADD_OKAY; import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED; @@ -148,6 +149,7 @@ import android.os.UEventObserver; import android.os.UserHandle; import android.os.VibrationEffect; import android.os.Vibrator; +import android.provider.DeviceConfig; import android.provider.MediaStore; import android.provider.Settings; import android.service.dreams.DreamManagerInternal; @@ -1378,12 +1380,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private long getScreenshotChordLongPressDelay() { + long delayMs = DeviceConfig.getLong( + DeviceConfig.NAMESPACE_SYSTEMUI, SCREENSHOT_KEYCHORD_DELAY, + ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout()); if (mKeyguardDelegate.isShowing()) { // Double the time it takes to take a screenshot from the keyguard - return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER * - ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout()); + return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER * delayMs); } - return ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout(); + return delayMs; } private long getRingerToggleChordDelay() { diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java index fdcadf3e3088..d6894cf2a4e8 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java @@ -33,6 +33,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import static com.android.server.location.LocationPermissions.PERMISSION_COARSE; import static com.android.server.location.LocationPermissions.PERMISSION_FINE; import static com.android.server.location.LocationUtils.createLocation; +import static com.android.server.location.listeners.RemoteListenerRegistration.IN_PROCESS_EXECUTOR; import static com.google.common.truth.Truth.assertThat; @@ -85,7 +86,6 @@ import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; import com.android.server.FgThread; import com.android.server.LocalServices; -import com.android.server.location.listeners.ListenerRegistration; import com.android.server.location.util.FakeUserInfoHelper; import com.android.server.location.util.TestInjector; @@ -484,7 +484,7 @@ public class LocationProviderManagerTest { PERMISSION_FINE, listener); CountDownLatch blocker = new CountDownLatch(1); - ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> { + IN_PROCESS_EXECUTOR.execute(() -> { try { blocker.await(); } catch (InterruptedException e) { @@ -622,7 +622,7 @@ public class LocationProviderManagerTest { PERMISSION_FINE, listener); CountDownLatch blocker = new CountDownLatch(1); - ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> { + IN_PROCESS_EXECUTOR.execute(() -> { try { blocker.await(); } catch (InterruptedException e) { diff --git a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java index 1ef12555a83a..69a9f4415fe7 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java @@ -16,6 +16,8 @@ package com.android.server.location.listeners; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -27,8 +29,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.testng.Assert.assertThrows; -import android.location.util.identity.CallerIdentity; -import android.os.Process; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -324,10 +324,8 @@ public class ListenerMultiplexerTest { boolean mActive = true; protected TestListenerRegistration(Integer integer, - Consumer<TestListenerRegistration> consumer, - boolean outOfProcess) { - super(integer, CallerIdentity.forTest(Process.myUid(), - Process.myPid() + (outOfProcess ? 1 : 0), "test", "test"), consumer); + Consumer<TestListenerRegistration> consumer) { + super(DIRECT_EXECUTOR, integer, consumer); } } @@ -345,7 +343,7 @@ public class ListenerMultiplexerTest { } public void addListener(Integer request, Consumer<TestListenerRegistration> consumer) { - addRegistration(consumer, new TestListenerRegistration(request, consumer, true)); + addRegistration(consumer, new TestListenerRegistration(request, consumer)); } public void removeListener(Consumer<TestListenerRegistration> consumer) { |