summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2022-01-30 23:30:08 -0800
committerLinux Build Service Account <lnxbuild@localhost>2022-01-30 23:30:08 -0800
commit05bdb5275f7e898a1474c0f1c9b22a16b07d436c (patch)
tree7c94a65e98b413c7cba14787da4a64673426cc24
parent73011a81de450dcef2aab91bed6fcccff4aca65d (diff)
parentc15cb12e3654220d105f3e3be1445b602415def0 (diff)
Merge c15cb12e3654220d105f3e3be1445b602415def0 on remote branch
Change-Id: I5cc503fe4edfdd717bd854359d0d88db1a75a0f9
-rw-r--r--core/java/android/app/Activity.java5
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java8
-rw-r--r--core/java/android/bluetooth/DeviceGroup.java6
-rw-r--r--core/java/android/util/BoostFramework.java3
-rw-r--r--core/java/android/view/ViewRootImpl.java36
-rw-r--r--core/res/res/values/config.xml9
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java58
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java5
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java72
-rw-r--r--services/core/java/com/android/server/media/MediaSession2Record.java6
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java118
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecordImpl.java7
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java3
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java18
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java53
-rwxr-xr-xservices/core/java/com/android/server/pm/PackageInstallerSession.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java4
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java6
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java14
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java4
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java39
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java2
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java26
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java10
35 files changed, 464 insertions, 164 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index db5dcc5c264b..af59ea1d22ff 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -77,7 +77,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
import android.os.PersistableBundle;
-import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -8788,9 +8787,7 @@ public class Activity extends ContextThemeWrapper
* the activity is visible after the screen is turned on when the lockscreen is up. In addition,
* if this flag is set and the activity calls {@link
* KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)}
- * the screen will turn on. If the screen is off and device is not secured, this flag can turn
- * screen on and dismiss keyguard to make this activity visible and resume, which can be used to
- * replace {@link PowerManager#ACQUIRE_CAUSES_WAKEUP}
+ * the screen will turn on.
*
* @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise.
*
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index a0d2977cf09a..01875eda2eca 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -16,6 +16,7 @@
package android.app.admin;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
@@ -77,6 +78,13 @@ public abstract class DevicePolicyManagerInternal {
OnCrossProfileWidgetProvidersChangeListener listener);
/**
+ * @param userHandle the handle of the user whose profile owner is being fetched.
+ * @return the configured supervision app if it exists and is the device owner or policy owner.
+ */
+ public abstract @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(
+ @NonNull UserHandle userHandle);
+
+ /**
* Checks if an app with given uid is an active device owner of its user.
*
* <p>This takes the DPMS lock. DO NOT call from PM/UM/AM with their lock held.
diff --git a/core/java/android/bluetooth/DeviceGroup.java b/core/java/android/bluetooth/DeviceGroup.java
index f1bd2c310197..0dac87f3d8f6 100644
--- a/core/java/android/bluetooth/DeviceGroup.java
+++ b/core/java/android/bluetooth/DeviceGroup.java
@@ -38,6 +38,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* Provides Device Group details.
@@ -53,7 +54,8 @@ public final class DeviceGroup implements Parcelable {
/** Size of the Device Group. */
private int mSize;
/** List of all group devices {@link BluetoothDevice} */
- private List <BluetoothDevice> mGroupDevices = new ArrayList<BluetoothDevice>();
+ private CopyOnWriteArrayList <BluetoothDevice> mGroupDevices
+ = new CopyOnWriteArrayList<BluetoothDevice>();
/** Primary Service UUID which has included required Device Group service*/
private final ParcelUuid mIncludingSrvcUUID;
/** Suggests whether exclusive access can be taken for this device group */
@@ -67,7 +69,7 @@ public final class DeviceGroup implements Parcelable {
ParcelUuid includingSrvcUUID, boolean exclusiveAccessSupport) {
mGroupId = groupId;
mSize = size;
- mGroupDevices = groupDevices;
+ mGroupDevices.addAll(groupDevices);
mIncludingSrvcUUID = includingSrvcUUID;
mExclusiveAccessSupport = exclusiveAccessSupport;
}
diff --git a/core/java/android/util/BoostFramework.java b/core/java/android/util/BoostFramework.java
index 461d67a8ae83..26964103132d 100644
--- a/core/java/android/util/BoostFramework.java
+++ b/core/java/android/util/BoostFramework.java
@@ -131,6 +131,9 @@ public class BoostFramework {
public static final int BOOST_GAME = 4;
public static final int RESERVED_1 = 5;
public static final int RESERVED_2 = 6;
+ public static final int RESERVED_3 = 7;
+ public static final int RESERVED_4 = 8;
+ public static final int RESERVED_5 = 9;
public static final int TYPE_SERVICE_START = 100;
public static final int TYPE_START_PROC = 101;
public static final int TYPE_START_APP_FROM_BG = 102;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e08420b75329..6152f5dd939b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -802,11 +802,7 @@ public final class ViewRootImpl implements ViewParent,
context);
mCompatibleVisibilityInfo = new SystemUiVisibilityInfo();
mAccessibilityManager = AccessibilityManager.getInstance(context);
- mAccessibilityManager.addAccessibilityStateChangeListener(
- mAccessibilityInteractionConnectionManager, mHandler);
mHighContrastTextManager = new HighContrastTextManager();
- mAccessibilityManager.addHighTextContrastStateChangeListener(
- mHighContrastTextManager, mHandler);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
@@ -1006,8 +1002,6 @@ public final class ViewRootImpl implements ViewParent,
mView = view;
mAttachInfo.mDisplayState = mDisplay.getState();
- mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
-
mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
@@ -1200,6 +1194,7 @@ public final class ViewRootImpl implements ViewParent,
"Unable to add window -- unknown error code " + res);
}
+ registerListeners();
if ((res & WindowManagerGlobal.ADD_FLAG_USE_BLAST) != 0) {
mUseBLASTAdapter = true;
}
@@ -1256,6 +1251,28 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ /**
+ * Register any kind of listeners if setView was success.
+ */
+ private void registerListeners() {
+ mAccessibilityManager.addAccessibilityStateChangeListener(
+ mAccessibilityInteractionConnectionManager, mHandler);
+ mAccessibilityManager.addHighTextContrastStateChangeListener(
+ mHighContrastTextManager, mHandler);
+ mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+ }
+
+ /**
+ * Unregister all listeners while detachedFromWindow.
+ */
+ private void unregisterListeners() {
+ mAccessibilityManager.removeAccessibilityStateChangeListener(
+ mAccessibilityInteractionConnectionManager);
+ mAccessibilityManager.removeHighTextContrastStateChangeListener(
+ mHighContrastTextManager);
+ mDisplayManager.unregisterDisplayListener(mDisplayListener);
+ }
+
private void setTag() {
final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
if (split.length > 0) {
@@ -4982,10 +4999,6 @@ public final class ViewRootImpl implements ViewParent,
}
mAccessibilityInteractionConnectionManager.ensureNoConnection();
- mAccessibilityManager.removeAccessibilityStateChangeListener(
- mAccessibilityInteractionConnectionManager);
- mAccessibilityManager.removeHighTextContrastStateChangeListener(
- mHighContrastTextManager);
removeSendWindowContentChangedCallback();
destroyHardwareRenderer();
@@ -5018,8 +5031,7 @@ public final class ViewRootImpl implements ViewParent,
mInputEventReceiver = null;
}
- mDisplayManager.unregisterDisplayListener(mDisplayListener);
-
+ unregisterListeners();
unscheduleTraversals();
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 33e38e066f21..831c59707645 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1911,8 +1911,9 @@
STREAM_MUSIC as if it's on TV platform. -->
<bool name="config_single_volume">false</bool>
- <!-- Flag indicating whether the volume panel should show remote sessions. -->
- <bool name="config_volumeShowRemoteSessions">true</bool>
+ <!-- Flag indicating whether platform level volume adjustments are enabled for remote sessions
+ on grouped devices. -->
+ <bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool>
<!-- Flag indicating that an outbound call must have a call capable phone account
that has declared it can process the call's handle. -->
@@ -5095,4 +5096,8 @@
<!-- the number of the max cached processes in the system. -->
<integer name="config_customizedMaxCachedProcesses">32</integer>
+
+ <!-- Maximum time in millisecs for telephony should wait to deactivate data call
+ when user turned off mobile data or data roaming during CIWLAN -->
+ <integer name="config_maximumDelayTimeToDeactivateDataCall">7000</integer>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bcd80ac1989e..0a1ac7931df9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4458,9 +4458,11 @@
<java-symbol type="dimen" name="config_wallpaperDimAmount" />
- <java-symbol type="bool" name="config_volumeShowRemoteSessions" />
+ <java-symbol type="bool" name="config_volumeAdjustmentForRemoteGroupSessions" />
<java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
<java-symbol type="color" name="overview_background"/>
+
+ <java-symbol type="integer" name="config_maximumDelayTimeToDeactivateDataCall" />
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index b7235a31af03..a568c28dacf1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -83,6 +83,19 @@ public class DisplayLayout {
private boolean mHasStatusBar = false;
private int mNavBarFrameHeight = 0;
+ /**
+ * Different from {@link #equals(Object)}, this method compares the basic geometry properties
+ * of two {@link DisplayLayout} objects including width, height, rotation, density and cutout.
+ * @return {@code true} if the given {@link DisplayLayout} is identical geometry wise.
+ */
+ public boolean isSameGeometry(@NonNull DisplayLayout other) {
+ return mWidth == other.mWidth
+ && mHeight == other.mHeight
+ && mRotation == other.mRotation
+ && mDensityDpi == other.mDensityDpi
+ && Objects.equals(mCutout, other.mCutout);
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 63f1985aa86e..8967457802a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -76,7 +76,6 @@ import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipUtils;
import java.io.PrintWriter;
-import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
@@ -441,7 +440,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
private void onDisplayChanged(DisplayLayout layout, boolean saveRestoreSnapFraction) {
- if (Objects.equals(layout, mPipBoundsState.getDisplayLayout())) {
+ if (mPipBoundsState.getDisplayLayout().isSameGeometry(layout)) {
return;
}
Runnable updateDisplayLayout = () -> {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 3c43f4a637ba..a383c1e2b680 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -70,6 +70,7 @@ public class InfoMediaManager extends MediaManager {
MediaRouter2Manager mRouterManager;
@VisibleForTesting
String mPackageName;
+ private final boolean mVolumeAdjustmentForRemoteGroupSessions;
private MediaDevice mCurrentConnectedDevice;
private LocalBluetoothManager mBluetoothManager;
@@ -83,6 +84,9 @@ public class InfoMediaManager extends MediaManager {
if (!TextUtils.isEmpty(packageName)) {
mPackageName = packageName;
}
+
+ mVolumeAdjustmentForRemoteGroupSessions = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
}
@Override
@@ -387,7 +391,9 @@ public class InfoMediaManager extends MediaManager {
@TargetApi(Build.VERSION_CODES.R)
boolean shouldEnableVolumeSeekBar(RoutingSessionInfo sessionInfo) {
- return false;
+ return sessionInfo.isSystemSession() // System sessions are not remote
+ || mVolumeAdjustmentForRemoteGroupSessions
+ || sessionInfo.getSelectedRoutes().size() <= 1;
}
private void refreshDevices() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index b2def7a8596a..802e5ebaf1c7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -75,6 +75,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
private final ActivityStarter mActivityStarter;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
private final boolean mAboveStatusbar;
+ private final boolean mVolumeAdjustmentForRemoteGroupSessions;
private final NotificationEntryManager mNotificationEntryManager;
@VisibleForTesting
final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
@@ -104,6 +105,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
mUiEventLogger = uiEventLogger;
+ mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
}
void start(@NonNull Callback cb) {
@@ -466,7 +469,9 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
}
boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
- return !isActiveRemoteDevice(device);
+ // TODO(b/202500642): Also enable volume control for remote non-group sessions.
+ return !isActiveRemoteDevice(device)
+ || mVolumeAdjustmentForRemoteGroupSessions;
}
private final MediaController.Callback mCb = new MediaController.Callback() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 70c21e43b79a..2c6e77c2444b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -108,6 +108,7 @@ public class NavigationBarView extends FrameLayout implements
private final int mNavColorSampleMargin;
private final SysUiState mSysUiFlagContainer;
+ // The current view is one of mHorizontal or mVertical depending on the current configuration
View mCurrentView = null;
private View mVertical;
private View mHorizontal;
@@ -370,12 +371,6 @@ public class NavigationBarView extends FrameLayout implements
}
}
- @Override
- protected boolean onSetAlpha(int alpha) {
- Log.e(TAG, "onSetAlpha", new Throwable());
- return super.onSetAlpha(alpha);
- }
-
public void setAutoHideController(AutoHideController autoHideController) {
mAutoHideController = autoHideController;
}
@@ -474,6 +469,18 @@ public class NavigationBarView extends FrameLayout implements
return mCurrentView;
}
+ /**
+ * Applies {@param consumer} to each of the nav bar views.
+ */
+ public void forEachView(Consumer<View> consumer) {
+ if (mVertical != null) {
+ consumer.accept(mVertical);
+ }
+ if (mHorizontal != null) {
+ consumer.accept(mHorizontal);
+ }
+ }
+
public RotationButtonController getRotationButtonController() {
return mRotationButtonController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 22cd6f86b165..79193564e21f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -49,6 +49,8 @@ import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.qti.extphone.ExtTelephonyManager;
+
import javax.inject.Inject;
import dagger.Lazy;
@@ -102,6 +104,10 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> {
mActivityStarter.postStartActivityDismissingKeyguard(
new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS), 0);
return;
+ } else if(!airplaneModeEnabled && TelephonyProperties.in_scbm().orElse(false)) {
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ new Intent(ExtTelephonyManager.ACTION_SHOW_NOTICE_SCM_BLOCK_OTHERS), 0);
+ return;
}
setEnabled(!airplaneModeEnabled);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index df445cbeb9e1..0e393bcc1b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -552,12 +552,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public void onStartedWakingUp() {
mStatusBar.getNotificationShadeWindowView().getWindowInsetsController()
.setAnimationsDisabled(false);
- View currentView = getCurrentNavBarView();
- if (currentView != null) {
- currentView.animate()
- .alpha(1f)
- .setDuration(NAV_BAR_CONTENT_FADE_DURATION)
- .start();
+ NavigationBarView navBarView = mStatusBar.getNavigationBarView();
+ if (navBarView != null) {
+ navBarView.forEachView(view ->
+ view.animate()
+ .alpha(1f)
+ .setDuration(NAV_BAR_CONTENT_FADE_DURATION)
+ .start());
}
}
@@ -565,12 +566,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public void onStartedGoingToSleep() {
mStatusBar.getNotificationShadeWindowView().getWindowInsetsController()
.setAnimationsDisabled(true);
- View currentView = getCurrentNavBarView();
- if (currentView != null) {
- currentView.animate()
- .alpha(0f)
- .setDuration(NAV_BAR_CONTENT_FADE_DURATION)
- .start();
+ NavigationBarView navBarView = mStatusBar.getNavigationBarView();
+ if (navBarView != null) {
+ navBarView.forEachView(view ->
+ view.animate()
+ .alpha(0f)
+ .setDuration(NAV_BAR_CONTENT_FADE_DURATION)
+ .start());
}
}
@@ -996,17 +998,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mStatusBar.onKeyguardViewManagerStatesUpdated();
}
- /**
- * Updates the visibility of the nav bar content views.
- */
- private void updateNavigationBarContentVisibility(boolean navBarContentVisible) {
- final NavigationBarView navBarView = mStatusBar.getNavigationBarView();
- if (navBarView != null && navBarView.getCurrentView() != null) {
- final View currentView = navBarView.getCurrentView();
- currentView.setVisibility(navBarContentVisible ? View.VISIBLE : View.INVISIBLE);
- }
- }
-
private View getCurrentNavBarView() {
final NavigationBarView navBarView = mStatusBar.getNavigationBarView();
return navBarView != null ? navBarView.getCurrentView() : null;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index e57059894786..cd6a77836304 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -33,7 +33,11 @@ import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.IVolumeController;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
+import android.media.RoutingSessionInfo;
import android.media.VolumePolicy;
+import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession.Token;
import android.net.Uri;
@@ -71,6 +75,7 @@ import com.android.systemui.util.concurrency.ThreadFactory;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -118,6 +123,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
private final Context mContext;
private final Looper mWorkerLooper;
private final PackageManager mPackageManager;
+ private final MediaRouter2Manager mRouter2Manager;
private final WakefulnessLifecycle mWakefulnessLifecycle;
private AudioManager mAudio;
private IAudioService mAudioService;
@@ -179,6 +185,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
mWorkerLooper = theadFactory.buildLooperOnNewThread(
VolumeDialogControllerImpl.class.getSimpleName());
mWorker = new W(mWorkerLooper);
+ mRouter2Manager = MediaRouter2Manager.getInstance(mContext);
mMediaSessionsCallbacksW = new MediaSessionsCallbacks(mContext);
mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW);
mAudio = audioManager;
@@ -1149,16 +1156,16 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>();
private int mNextStream = DYNAMIC_STREAM_START_INDEX;
- private final boolean mShowRemoteSessions;
+ private final boolean mVolumeAdjustmentForRemoteGroupSessions;
public MediaSessionsCallbacks(Context context) {
- mShowRemoteSessions = context.getResources().getBoolean(
- com.android.internal.R.bool.config_volumeShowRemoteSessions);
+ mVolumeAdjustmentForRemoteGroupSessions = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
}
@Override
public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
- if (mShowRemoteSessions) {
+ if (showForSession(token)) {
addStream(token, "onRemoteUpdate");
int stream = 0;
@@ -1190,7 +1197,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
@Override
public void onRemoteVolumeChanged(Token token, int flags) {
- if (mShowRemoteSessions) {
+ if (showForSession(token)) {
addStream(token, "onRemoteVolumeChanged");
int stream = 0;
synchronized (mRemoteStreams) {
@@ -1214,7 +1221,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
@Override
public void onRemoteRemoved(Token token) {
- if (mShowRemoteSessions) {
+ if (showForSession(token)) {
int stream = 0;
synchronized (mRemoteStreams) {
if (!mRemoteStreams.containsKey(token)) {
@@ -1233,14 +1240,41 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
}
public void setStreamVolume(int stream, int level) {
- if (mShowRemoteSessions) {
- final Token t = findToken(stream);
- if (t == null) {
- Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
- return;
+ final Token token = findToken(stream);
+ if (token == null) {
+ Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
+ return;
+ }
+ if (showForSession(token)) {
+ mMediaSessions.setVolume(token, level);
+ }
+ }
+
+ private boolean showForSession(Token token) {
+ if (mVolumeAdjustmentForRemoteGroupSessions) {
+ return true;
+ }
+ MediaController ctr = new MediaController(mContext, token);
+ String packageName = ctr.getPackageName();
+ List<RoutingSessionInfo> sessions =
+ mRouter2Manager.getRoutingSessions(packageName);
+ boolean foundNonSystemSession = false;
+ boolean isGroup = false;
+ for (RoutingSessionInfo session : sessions) {
+ if (!session.isSystemSession()) {
+ foundNonSystemSession = true;
+ int selectedRouteCount = session.getSelectedRoutes().size();
+ if (selectedRouteCount > 1) {
+ isGroup = true;
+ break;
+ }
}
- mMediaSessions.setVolume(t, level);
}
+ if (!foundNonSystemSession) {
+ Log.d(TAG, "No routing session for " + packageName);
+ return false;
+ }
+ return !isGroup;
}
private Token findToken(int stream) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 5c0efd36fcd1..c9462d651bc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -101,6 +101,11 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
// Initial non-set value
when(mRingerModeLiveData.getValue()).thenReturn(-1);
when(mRingerModeInternalLiveData.getValue()).thenReturn(-1);
+ // Enable group volume adjustments
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions,
+ true);
+
mCallback = mock(VolumeDialogControllerImpl.C.class);
mThreadFactory.setLooper(TestableLooper.get(this).getLooper());
mVolumeController = new TestableVolumeDialogControllerImpl(mContext,
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 1dd90484672f..774415221482 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -323,9 +323,11 @@ public class BtHelper {
return AudioSystem.bluetoothCodecToAudioFormat(btCodecConfig.getCodecType());
}
- //SCO device tracking for TWSPLUS device
+ //SCO device tracking for TWSPLUS or GROUP device
private HashMap<BluetoothDevice, Integer> mScoClientDevices =
new HashMap<BluetoothDevice, Integer>();
+ private static final int GROUP_ID_START = 0;
+ private static final int GROUP_ID_END = 15;
private void updateTwsPlusScoState(BluetoothDevice device, Integer state) {
if (mScoClientDevices.containsKey(device)) {
@@ -392,6 +394,68 @@ public class BtHelper {
return ret;
}
+ private boolean isGroupDevice(BluetoothDevice device) {
+ int type = device.getDeviceType();
+ boolean ret = false;
+ Log.i(TAG, "Bluetooth device type: " + type);
+ if (type >= GROUP_ID_START && type <= GROUP_ID_END)
+ ret = true;
+ Log.i(TAG, "isGroupDevice return " + ret);
+ return ret;
+ }
+
+ private void updateGroupScoState(BluetoothDevice device, Integer state) {
+ if (mScoClientDevices.containsKey(device)) {
+ Integer prevState = mScoClientDevices.get(device);
+ Log.i(TAG, "updateGroupScoState: prevState: " + prevState + "state: " + state);
+ if (state != prevState) {
+ mScoClientDevices.remove(device);
+ mScoClientDevices.put(device, state);
+ }
+ } else {
+ mScoClientDevices.put(device, state);
+ }
+ }
+
+ private boolean checkAndUpdateGroupScoState(Intent intent, Integer state) {
+ //default ret value is true
+ //so that legacy devices fallsthru
+ boolean ret = true;
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ Log.i(TAG, "device:" + device);
+
+ if (device == null) {
+ Log.e(TAG, "checkAndUpdateGroupScoState: device is null");
+ //intent cant have device has null
+ //in case it is treat them as non-twsplus case and return true
+ return ret;
+ }
+
+ if (isGroupDevice(device)) {
+ if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
+ //if adding new Device
+ //check if there is no device already connected
+ if (isAudioPathUp()) {
+ Log.i(TAG, "No need to bringup audio-path");
+ ret = false;
+ }
+ //Update the States now
+ updateGroupScoState(device, state);
+ } else {
+ //For disconnect cases, update the state first
+ updateGroupScoState(device, state);
+ //if deleting new Device
+ //check if all devices are disconnected
+ if (isAudioPathUp()) {
+ Log.i(TAG, "not good to tear down audio-path");
+ ret = false;
+ }
+ }
+ }
+ Log.i(TAG, "checkAndUpdateGroupScoState returns " + ret);
+ return ret;
+ }
+
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void receiveBtEvent(Intent intent) {
@@ -409,6 +473,8 @@ public class BtHelper {
switch (btState) {
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
if (checkAndUpdatTwsPlusScoState(intent,
+ BluetoothHeadset.STATE_AUDIO_CONNECTED) &&
+ checkAndUpdateGroupScoState(intent,
BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
@@ -429,7 +495,9 @@ public class BtHelper {
break;
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
if (checkAndUpdatTwsPlusScoState(intent,
- BluetoothHeadset.STATE_AUDIO_DISCONNECTED)) {
+ BluetoothHeadset.STATE_AUDIO_DISCONNECTED) &&
+ checkAndUpdateGroupScoState(intent,
+ BluetoothHeadset.STATE_AUDIO_DISCONNECTED)) {
mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
// There are two cases where we want to immediately reconnect audio:
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index 607218e20ea8..b424c2083bd4 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -146,6 +146,12 @@ public class MediaSession2Record implements MediaSessionRecordImpl {
}
@Override
+ public boolean canHandleVolumeKey() {
+ // TODO: Implement when MediaSession2 starts to get key events.
+ return false;
+ }
+
+ @Override
public int getSessionPolicies() {
synchronized (mLock) {
return mPolicies;
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 1525cd4da669..4822d6a62ac7 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -26,7 +26,9 @@ import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.MediaMetadata;
+import android.media.MediaRouter2Manager;
import android.media.Rating;
+import android.media.RoutingSessionInfo;
import android.media.VolumeProvider;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
@@ -50,6 +52,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
+import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@@ -121,6 +124,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
private final SessionCb mSessionCb;
private final MediaSessionService mService;
private final Context mContext;
+ private final boolean mVolumeAdjustmentForRemoteGroupSessions;
private final Object mLock = new Object();
private final CopyOnWriteArrayList<ISessionControllerCallbackHolder>
@@ -180,6 +184,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mAudioAttrs = DEFAULT_ATTRIBUTES;
mPolicies = policies;
+ mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
// May throw RemoteException if the session app is killed.
mSessionCb.mCb.asBinder().linkToDeath(this, 0);
@@ -285,35 +291,39 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
asSystemService, useSuggested, previousFlagPlaySound);
} else {
if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
- // Nothing to do, the volume cannot be changed
- return;
- }
- if (direction == AudioManager.ADJUST_TOGGLE_MUTE
+ if (DEBUG) {
+ Log.d(TAG, "Session does not support volume adjustment");
+ }
+ } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE
|| direction == AudioManager.ADJUST_MUTE
|| direction == AudioManager.ADJUST_UNMUTE) {
Log.w(TAG, "Muting remote playback is not supported");
- return;
- }
- if (DEBUG) {
- Log.w(TAG, "adjusting volume, pkg=" + packageName + ", asSystemService="
- + asSystemService + ", dir=" + direction);
- }
- mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction);
+ } else {
+ if (DEBUG) {
+ Log.w(TAG, "adjusting volume, pkg=" + packageName + ", asSystemService="
+ + asSystemService + ", dir=" + direction);
+ }
+ mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction);
+
+ int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
+ mOptimisticVolume = volumeBefore + direction;
+ mOptimisticVolume = Math.max(0, Math.min(mOptimisticVolume, mMaxVolume));
+ mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
+ mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
+ if (volumeBefore != mOptimisticVolume) {
+ pushVolumeUpdate();
+ }
- int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
- mOptimisticVolume = volumeBefore + direction;
- mOptimisticVolume = Math.max(0, Math.min(mOptimisticVolume, mMaxVolume));
- mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
- mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
- if (volumeBefore != mOptimisticVolume) {
- pushVolumeUpdate();
+ if (DEBUG) {
+ Log.d(TAG, "Adjusted optimistic volume to " + mOptimisticVolume + " max is "
+ + mMaxVolume);
+ }
}
+ // Always notify, even if the volume hasn't changed. This is important to ensure that
+ // System UI receives an event if a hardware volume key is pressed but the session that
+ // handles it does not allow volume adjustment. Without such an event, System UI would
+ // not show volume controls to the user.
mService.notifyRemoteVolumeChanged(flags, this);
-
- if (DEBUG) {
- Log.d(TAG, "Adjusted optimistic volume to " + mOptimisticVolume + " max is "
- + mMaxVolume);
- }
}
}
@@ -337,25 +347,28 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
});
} else {
if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) {
- // Nothing to do. The volume can't be set directly.
- return;
- }
- value = Math.max(0, Math.min(value, mMaxVolume));
- mSessionCb.setVolumeTo(packageName, pid, uid, value);
+ if (DEBUG) {
+ Log.d(TAG, "Session does not support setting volume");
+ }
+ } else {
+ value = Math.max(0, Math.min(value, mMaxVolume));
+ mSessionCb.setVolumeTo(packageName, pid, uid, value);
+
+ int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
+ mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume));
+ mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
+ mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
+ if (volumeBefore != mOptimisticVolume) {
+ pushVolumeUpdate();
+ }
- int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
- mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume));
- mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
- mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
- if (volumeBefore != mOptimisticVolume) {
- pushVolumeUpdate();
+ if (DEBUG) {
+ Log.d(TAG, "Set optimistic volume to " + mOptimisticVolume + " max is "
+ + mMaxVolume);
+ }
}
+ // Always notify, even if the volume hasn't changed.
mService.notifyRemoteVolumeChanged(flags, this);
-
- if (DEBUG) {
- Log.d(TAG, "Set optimistic volume to " + mOptimisticVolume + " max is "
- + mMaxVolume);
- }
}
}
@@ -449,6 +462,33 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
}
@Override
+ public boolean canHandleVolumeKey() {
+ if (isPlaybackTypeLocal() || mVolumeAdjustmentForRemoteGroupSessions) {
+ return true;
+ }
+ MediaRouter2Manager mRouter2Manager = MediaRouter2Manager.getInstance(mContext);
+ List<RoutingSessionInfo> sessions =
+ mRouter2Manager.getRoutingSessions(mPackageName);
+ boolean foundNonSystemSession = false;
+ boolean isGroup = false;
+ for (RoutingSessionInfo session : sessions) {
+ if (!session.isSystemSession()) {
+ foundNonSystemSession = true;
+ int selectedRouteCount = session.getSelectedRoutes().size();
+ if (selectedRouteCount > 1) {
+ isGroup = true;
+ break;
+ }
+ }
+ }
+ if (!foundNonSystemSession) {
+ Log.d(TAG, "No routing session for " + mPackageName);
+ return false;
+ }
+ return !isGroup;
+ }
+
+ @Override
public int getSessionPolicies() {
synchronized (mLock) {
return mPolicies;
diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
index 3c50597b8cfc..8f01f02f2ab1 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
@@ -131,6 +131,13 @@ public interface MediaSessionRecordImpl extends AutoCloseable {
KeyEvent ke, int sequenceId, ResultReceiver cb);
/**
+ * Returns whether the media session can handle volume key events.
+ *
+ * @return True if this media session can handle volume key events, false otherwise.
+ */
+ boolean canHandleVolumeKey();
+
+ /**
* Get session policies from custom policy provider set when MediaSessionRecord is instantiated.
* If custom policy does not exist, will return null.
*/
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index c4c21df746b3..b75ba75e028b 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -325,8 +325,7 @@ class MediaSessionStack {
int size = records.size();
for (int i = 0; i < size; i++) {
MediaSessionRecord record = records.get(i);
- // Do not send the volume key events to remote sessions.
- if (record.checkPlaybackActiveState(true) && record.isPlaybackTypeLocal()) {
+ if (record.checkPlaybackActiveState(true) && record.canHandleVolumeKey()) {
mCachedVolumeDefault = record;
return record;
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 27b164830572..ee0b3d52eb3d 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -71,6 +71,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -81,7 +82,6 @@ import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
-
import com.android.server.pm.UserManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -285,6 +285,12 @@ public final class OverlayManagerService extends SystemService {
restoreSettings();
+ // Wipe all shell overlays on boot, to recover from a potentially broken device
+ String shellPkgName = TextUtils.emptyIfNull(
+ getContext().getString(android.R.string.config_systemShell));
+ mSettings.removeIf(overlayInfo -> overlayInfo.isFabricated
+ && shellPkgName.equals(overlayInfo.packageName));
+
initIfNeeded();
onSwitchUser(UserHandle.USER_SYSTEM);
@@ -891,6 +897,16 @@ public final class OverlayManagerService extends SystemService {
throw new IllegalArgumentException(request.typeToString()
+ " unsupported for user " + request.userId);
}
+
+ // Normal apps are blocked from accessing OMS via SELinux, so to block non-root,
+ // non privileged callers, a simple check against the shell UID is sufficient, since
+ // that's the only exception from the other categories. This is enough while OMS
+ // is not a public API, but this will have to be changed if it's ever exposed.
+ if (callingUid == Process.SHELL_UID) {
+ EventLog.writeEvent(0x534e4554, "202768292", -1, "");
+ throw new IllegalArgumentException("Non-root shell cannot fabricate overlays");
+ }
+
realUserId = UserHandle.USER_ALL;
// Enforce that the calling process can only register and unregister fabricated
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 51fea8219d02..f317d311c87a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -135,6 +135,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50;
/** Upper bound on number of historical sessions for a UID */
private static final long MAX_HISTORICAL_SESSIONS = 1048576;
+ /** Destroy sessions older than this on storage free request */
+ private static final long MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS = 8 * DateUtils.HOUR_IN_MILLIS;
/**
* Allow verification-skipping if it's a development app installed through ADB with
@@ -334,22 +336,28 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
@GuardedBy("mSessions")
private void reconcileStagesLocked(String volumeUuid) {
- final File stagingDir = getTmpSessionDir(volumeUuid);
- final ArraySet<File> unclaimedStages = newArraySet(
- stagingDir.listFiles(sStageFilter));
-
- // We also need to clean up orphaned staging directory for staged sessions
- final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
- unclaimedStages.addAll(newArraySet(stagedSessionStagingDir.listFiles()));
-
+ final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid);
// Ignore stages claimed by active sessions
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
unclaimedStages.remove(session.stageDir);
}
+ removeStagingDirs(unclaimedStages);
+ }
+
+ private ArraySet<File> getStagingDirsOnVolume(String volumeUuid) {
+ final File stagingDir = getTmpSessionDir(volumeUuid);
+ final ArraySet<File> stagingDirs = newArraySet(stagingDir.listFiles(sStageFilter));
+
+ // We also need to clean up orphaned staging directory for staged sessions
+ final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
+ stagingDirs.addAll(newArraySet(stagedSessionStagingDir.listFiles()));
+ return stagingDirs;
+ }
+ private void removeStagingDirs(ArraySet<File> stagingDirsToRemove) {
// Clean up orphaned staging directories
- for (File stage : unclaimedStages) {
+ for (File stage : stagingDirsToRemove) {
Slog.w(TAG, "Deleting orphan stage " + stage);
synchronized (mPm.mInstallLock) {
mPm.removeCodePathLI(stage);
@@ -363,6 +371,33 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
+ /**
+ * Called to free up some storage space from obsolete installation files
+ */
+ public void freeStageDirs(String volumeUuid) {
+ final ArraySet<File> unclaimedStagingDirsOnVolume = getStagingDirsOnVolume(volumeUuid);
+ final long currentTimeMillis = System.currentTimeMillis();
+ synchronized (mSessions) {
+ for (int i = 0; i < mSessions.size(); i++) {
+ final PackageInstallerSession session = mSessions.valueAt(i);
+ if (!unclaimedStagingDirsOnVolume.contains(session.stageDir)) {
+ // Only handles sessions stored on the target volume
+ continue;
+ }
+ final long age = currentTimeMillis - session.createdMillis;
+ if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) {
+ // Aggressively close old sessions because we are running low on storage
+ // Their staging dirs will be removed too
+ session.abandon();
+ } else {
+ // Session is new enough, so it deserves to be kept even on low storage
+ unclaimedStagingDirsOnVolume.remove(session.stageDir);
+ }
+ }
+ }
+ removeStagingDirs(unclaimedStagingDirsOnVolume);
+ }
+
public static boolean isStageName(String name) {
final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ad940e6a6030..d62cb10c0a86 100755
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -681,7 +681,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final Runnable r;
synchronized (mLock) {
assertNotChildLocked("StagedSession#abandon");
- assertCallerIsOwnerOrRoot();
+ assertCallerIsOwnerOrRootOrSystem();
if (isInTerminalState()) {
// We keep the session in the database if it's in a finalized state. It will be
// removed by PackageInstallerService when the last update time is old enough.
@@ -3725,7 +3725,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
synchronized (mLock) {
assertNotChildLocked("abandonNonStaged");
- assertCallerIsOwnerOrRoot();
+ assertCallerIsOwnerOrRootOrSystem();
if (mRelinquished) {
if (LOGD) Slog.d(TAG, "Ignoring abandon after commit relinquished control");
return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3da669145363..1d14bb59c56a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9413,6 +9413,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (freeBytesRequired > 0) {
smInternal.freeCache(volumeUuid, freeBytesRequired);
}
+
+ // 12. Clear temp install session files
+ mInstallerService.freeStageDirs(volumeUuid);
+
if (file.getUsableSpace() >= bytes) return;
} else {
try {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2648e1b6d2c9..138d55e09742 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4648,6 +4648,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return mKeyguardDelegate.isInputRestricted();
}
+ /** {@inheritDoc} */
+ @Override
+ public boolean isKeyguardUnoccluding() {
+ return keyguardOn() && !mWindowManagerFuncs.isAppTransitionStateIdle();
+ }
+
@Override
public void dismissKeyguardLw(IKeyguardDismissCallback callback, CharSequence message) {
if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 78b03b2b88e7..510ab93e1af5 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -367,6 +367,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* as the top display.
*/
void moveDisplayToTop(int displayId);
+
+ /**
+ * Return whether the app transition state is idle.
+ * @return {@code true} if app transition state is idle on the default display.
+ */
+ boolean isAppTransitionStateIdle();
}
/**
@@ -974,6 +980,14 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public boolean isKeyguardOccluded();
/**
+ * Return whether the keyguard is unoccluding.
+ * @return {@code true} if the keyguard is unoccluding.
+ */
+ default boolean isKeyguardUnoccluding() {
+ return false;
+ }
+
+ /**
* @return true if in keyguard is on.
*/
boolean isKeyguardShowing();
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c1b287ff8077..c61cfeeac917 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -365,6 +365,10 @@ public class AppTransition implements Dump {
setAppTransitionState(APP_STATE_IDLE);
}
+ boolean isIdle() {
+ return mAppTransitionState == APP_STATE_IDLE;
+ }
+
boolean isTimeout() {
return mAppTransitionState == APP_STATE_TIMEOUT;
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index cf0f973fa7db..054854aef121 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -190,8 +190,7 @@ class KeyguardController {
if (keyguardChanged) {
// Irrelevant to AOD.
- dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */,
- false /* turningScreenOn */);
+ dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */);
mKeyguardGoingAway = false;
if (keyguardShowing) {
mDismissalRequested = false;
@@ -385,6 +384,8 @@ class KeyguardController {
mService.continueWindowLayout();
}
}
+ dismissMultiWindowModeForTaskIfNeeded(topActivity != null
+ ? topActivity.getRootTask() : null);
}
/**
@@ -410,21 +411,6 @@ class KeyguardController {
}
}
- /**
- * Called when somebody wants to turn screen on.
- */
- private void handleTurnScreenOn(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
-
- mTaskSupervisor.wakeUp("handleTurnScreenOn");
- if (mKeyguardShowing && canDismissKeyguard()) {
- mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
- mDismissalRequested = true;
- }
- }
-
boolean isDisplayOccluded(int displayId) {
return getDisplayState(displayId).mOccluded;
}
@@ -438,11 +424,9 @@ class KeyguardController {
}
private void dismissMultiWindowModeForTaskIfNeeded(
- @Nullable Task currentTaskControllingOcclusion, boolean turningScreenOn) {
- // If turningScreenOn is true, it means that the visibility state has changed from
- // currentTaskControllingOcclusion and we should update windowing mode.
+ @Nullable Task currentTaskControllingOcclusion) {
// TODO(b/113840485): Handle docked stack for individual display.
- if (!turningScreenOn && (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY))) {
+ if (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) {
return;
}
@@ -581,26 +565,17 @@ class KeyguardController {
&& controller.mWindowManager.isKeyguardSecure(
controller.mService.getCurrentUserId());
- boolean occludingChange = false;
- boolean turningScreenOn = false;
if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
&& mTopTurnScreenOnActivity != null
&& !mService.mWindowManager.mPowerManager.isInteractive()
- && (mRequestDismissKeyguard || occludedByActivity
- || controller.canDismissKeyguard())) {
- turningScreenOn = true;
- controller.handleTurnScreenOn(mDisplayId);
+ && (mRequestDismissKeyguard || occludedByActivity)) {
+ controller.mTaskSupervisor.wakeUp("handleTurnScreenOn");
mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
}
if (lastOccluded != mOccluded) {
- occludingChange = true;
controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
}
-
- if (occludingChange || turningScreenOn) {
- controller.dismissMultiWindowModeForTaskIfNeeded(task, turningScreenOn);
- }
}
/**
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 4ff6d3c9a5f2..1f2a9a29932c 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -159,7 +159,8 @@ class WallpaperController {
boolean needsShowWhenLockedWallpaper = false;
if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
&& mService.mPolicy.isKeyguardLocked()
- && mService.mPolicy.isKeyguardOccluded()) {
+ && (mService.mPolicy.isKeyguardOccluded()
+ || mService.mPolicy.isKeyguardUnoccluding())) {
// The lowest show when locked window decides whether we need to put the wallpaper
// behind.
needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2705c0b1dec2..1289ca3804e6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3075,6 +3075,11 @@ public class WindowManagerService extends IWindowManager.Stub
syncInputTransactions(true /* waitForAnimations */);
}
+ @Override
+ public boolean isAppTransitionStateIdle() {
+ return getDefaultDisplayContentLocked().mAppTransition.isIdle();
+ }
+
/**
* Notifies activity manager that some Keyguard flags have changed and that it needs to
* reevaluate the visibilities of the activities.
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d48c9ea4831c..99e28d101496 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -12647,6 +12647,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(
+ @NonNull UserHandle userHandle) {
+ return DevicePolicyManagerService.this.getProfileOwnerOrDeviceOwnerSupervisionComponent(
+ userHandle);
+ }
+
+ @Override
public boolean isActiveDeviceOwner(int uid) {
return isDeviceOwner(new CallerIdentity(uid, null, null));
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java
index 24c58f49bed6..7358551d1bc5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java
@@ -72,7 +72,7 @@ public class UserUsageStatsServiceTest {
HashMap<String, Long> installedPkgs = new HashMap<>();
installedPkgs.put(TEST_PACKAGE_NAME, System.currentTimeMillis());
- mService.init(System.currentTimeMillis(), installedPkgs);
+ mService.init(System.currentTimeMillis(), installedPkgs, true);
}
@After
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 1b8492722c10..ac1fcce20dc0 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -380,6 +380,7 @@ public class UsageStatsService extends SystemService implements
if (userId == UserHandle.USER_SYSTEM) {
UsageStatsIdleService.scheduleUpdateMappingsJob(getContext());
}
+ final boolean deleteObsoleteData = shouldDeleteObsoleteData(UserHandle.of(userId));
synchronized (mLock) {
// This should be safe to add this early. Other than reportEventOrAddToQueue, every
// other user grabs the lock before accessing
@@ -402,7 +403,7 @@ public class UsageStatsService extends SystemService implements
boolean needToFlush = !pendingEvents.isEmpty();
initializeUserUsageStatsServiceLocked(userId, System.currentTimeMillis(),
- installedPackages);
+ installedPackages, deleteObsoleteData);
final UserUsageStatsService userService = getUserUsageStatsServiceLocked(userId);
if (userService == null) {
Slog.i(TAG, "Attempted to unlock stopped or removed user " + userId);
@@ -596,13 +597,13 @@ public class UsageStatsService extends SystemService implements
* when the user is initially unlocked.
*/
private void initializeUserUsageStatsServiceLocked(int userId, long currentTimeMillis,
- HashMap<String, Long> installedPackages) {
+ HashMap<String, Long> installedPackages, boolean deleteObsoleteData) {
final File usageStatsDir = new File(Environment.getDataSystemCeDirectory(userId),
"usagestats");
final UserUsageStatsService service = new UserUsageStatsService(getContext(), userId,
usageStatsDir, this);
try {
- service.init(currentTimeMillis, installedPackages);
+ service.init(currentTimeMillis, installedPackages, deleteObsoleteData);
mUserState.put(userId, service);
} catch (Exception e) {
if (mUserManager.isUserUnlocked(userId)) {
@@ -1165,6 +1166,10 @@ public class UsageStatsService extends SystemService implements
* Called by the Binder stub.
*/
private boolean updatePackageMappingsData() {
+ // don't update the mappings if a profile user is defined
+ if (!shouldDeleteObsoleteData(UserHandle.SYSTEM)) {
+ return true; // return true so job scheduler doesn't reschedule the job
+ }
// fetch the installed packages outside the lock so it doesn't block package manager.
final HashMap<String, Long> installedPkgs = getInstalledPackages(UserHandle.USER_SYSTEM);
synchronized (mLock) {
@@ -1309,6 +1314,13 @@ public class UsageStatsService extends SystemService implements
}
}
+ private boolean shouldDeleteObsoleteData(UserHandle userHandle) {
+ final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
+ // If a profile owner is not defined for the given user, obsolete data should be deleted
+ return dpmInternal == null
+ || dpmInternal.getProfileOwnerOrDeviceOwnerSupervisionComponent(userHandle) == null;
+ }
+
private String buildFullToken(String packageName, String token) {
final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1);
sb.append(packageName);
@@ -2532,8 +2544,12 @@ public class UsageStatsService extends SystemService implements
private class MyPackageMonitor extends PackageMonitor {
@Override
public void onPackageRemoved(String packageName, int uid) {
- mHandler.obtainMessage(MSG_PACKAGE_REMOVED, getChangingUserId(), 0, packageName)
- .sendToTarget();
+ final int changingUserId = getChangingUserId();
+ // Only remove the package's data if a profile owner is not defined for the user
+ if (shouldDeleteObsoleteData(UserHandle.of(changingUserId))) {
+ mHandler.obtainMessage(MSG_PACKAGE_REMOVED, changingUserId, 0, packageName)
+ .sendToTarget();
+ }
super.onPackageRemoved(packageName, uid);
}
}
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 36d8c857ca21..fee4a47fd6ff 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -115,8 +115,9 @@ class UserUsageStatsService {
mSystemTimeSnapshot = System.currentTimeMillis();
}
- void init(final long currentTimeMillis, HashMap<String, Long> installedPackages) {
- readPackageMappingsLocked(installedPackages);
+ void init(final long currentTimeMillis, HashMap<String, Long> installedPackages,
+ boolean deleteObsoleteData) {
+ readPackageMappingsLocked(installedPackages, deleteObsoleteData);
mDatabase.init(currentTimeMillis);
if (mDatabase.wasUpgradePerformed()) {
mDatabase.prunePackagesDataOnUpgrade(installedPackages);
@@ -180,12 +181,13 @@ class UserUsageStatsService {
return mDatabase.onPackageRemoved(packageName, timeRemoved);
}
- private void readPackageMappingsLocked(HashMap<String, Long> installedPackages) {
+ private void readPackageMappingsLocked(HashMap<String, Long> installedPackages,
+ boolean deleteObsoleteData) {
mDatabase.readMappingsLocked();
// Package mappings for the system user are updated after 24 hours via a job scheduled by
// UsageStatsIdleService to ensure restored data is not lost on first boot. Additionally,
// this makes user service initialization a little quicker on subsequent boots.
- if (mUserId != UserHandle.USER_SYSTEM) {
+ if (mUserId != UserHandle.USER_SYSTEM && deleteObsoleteData) {
updatePackageMappingsLocked(installedPackages);
}
}