diff options
42 files changed, 1332 insertions, 867 deletions
diff --git a/Android.bp b/Android.bp index ae34005ddd02..b30bdaa37246 100644 --- a/Android.bp +++ b/Android.bp @@ -485,7 +485,6 @@ java_library { "//frameworks/base/apex/permission/framework", "//frameworks/base/apex/statsd/service", "//frameworks/base/telephony", - "//frameworks/base/wifi", "//frameworks/opt/net/wifi/service", ], } @@ -512,8 +511,7 @@ java_library { "framework-sdkextensions-stubs-systemapi", // TODO(b/146167933): Use framework-statsd-stubs instead. "framework-statsd", - // TODO(b/140299412): should be framework-wifi-stubs - "framework-wifi", + "framework-wifi-stubs", "ike-stubs", // TODO(b/147200698): should be the stub of framework-tethering "framework-tethering", @@ -552,7 +550,8 @@ java_library { "compat-changeid-annotation-processor", ], static_libs: [ - "exoplayer2-core" + "exoplayer2-core", + "android.hardware.wifi-V1.0-java-constants", ] } @@ -1217,7 +1216,7 @@ java_library { "core/java/com/android/internal/util/Protocol.java", "core/java/com/android/internal/util/Preconditions.java", "telephony/java/android/telephony/Annotation.java", - ":net-utils-framework-wifi-common-srcs", + ":net-utils-framework-wifi-common-srcs", ], libs: [ "framework-annotations-lib", @@ -1244,6 +1243,7 @@ filegroup { "core/java/com/android/internal/util/StateMachine.java", "core/java/com/android/internal/util/WakeupMessage.java", ], + visibility: ["//frameworks/opt/net/wifi/service"], } // TODO(b/145644363): move this to under StubLibraries.bp or ApiDocs.bp diff --git a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java index f32bf9a4b9e6..c62aad622f25 100644 --- a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java @@ -20,6 +20,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import android.app.Activity; import android.content.Context; +import android.graphics.Point; import android.graphics.Rect; import android.os.RemoteException; import android.perftests.utils.BenchmarkState; @@ -149,7 +150,7 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase { mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrame, mOutContentInsets, mOutVisibleInsets, mOutStableInsets, mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration, - mOutSurfaceControl, mOutInsetsState); + mOutSurfaceControl, mOutInsetsState, new Point()); } } } diff --git a/api/current.txt b/api/current.txt index 815bbf82fa71..636ac72aa544 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25779,10 +25779,12 @@ package android.media { field public static final int COLOR_TRANSFER_LINEAR = 1; // 0x1 field public static final int COLOR_TRANSFER_SDR_VIDEO = 3; // 0x3 field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6 + field public static final String KEY_AAC_DRC_ALBUM_MODE = "aac-drc-album-mode"; field public static final String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level"; field public static final String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level"; field public static final String KEY_AAC_DRC_EFFECT_TYPE = "aac-drc-effect-type"; field public static final String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression"; + field public static final String KEY_AAC_DRC_OUTPUT_LOUDNESS = "aac-drc-output-loudness"; field public static final String KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level"; field public static final String KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level"; field public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count"; diff --git a/api/system-current.txt b/api/system-current.txt index b261b3e71d75..ef9a4e4fb100 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6877,6 +6877,11 @@ package android.net.wifi { method public boolean satisfiedBy(android.net.NetworkSpecifier); } + public final class WifiNetworkSuggestion implements android.os.Parcelable { + method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfiguration(); + method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration(); + } + public static final class WifiNetworkSuggestion.Builder { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int); } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 9a76a1b4eb79..e3fd8d297316 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -31,6 +31,7 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.PixelFormat; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; @@ -188,6 +189,7 @@ public abstract class WallpaperService extends Service { DisplayCutout mDispatchedDisplayCutout = DisplayCutout.NO_CUTOUT; final InsetsState mInsetsState = new InsetsState(); final MergedConfiguration mMergedConfiguration = new MergedConfiguration(); + private final Point mSurfaceSize = new Point(); final WindowManager.LayoutParams mLayout = new WindowManager.LayoutParams(); @@ -838,12 +840,13 @@ public abstract class WallpaperService extends Service { } else { mLayout.surfaceInsets.set(0, 0, 0, 0); } + final int relayoutResult = mSession.relayout( mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, View.VISIBLE, 0, -1, mWinFrame, mContentInsets, mVisibleInsets, mStableInsets, mBackdropFrame, mDisplayCutout, mMergedConfiguration, mSurfaceControl, - mInsetsState); + mInsetsState, mSurfaceSize); if (mSurfaceControl.isValid()) { mSurfaceHolder.mSurface.copyFrom(mSurfaceControl); mSurfaceControl.release(); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 8f25d89fe08c..e3446e1f7b57 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -18,6 +18,7 @@ package android.view; import android.content.ClipData; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.os.Bundle; @@ -90,6 +91,7 @@ interface IWindowSession { * since it was last displayed. * @param outSurface Object in which is placed the new display surface. * @param insetsState The current insets state in the system. + * @param outSurfaceSize The width and height of the surface control * * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS}, * {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}. @@ -101,7 +103,7 @@ interface IWindowSession { out Rect outBackdropFrame, out DisplayCutout.ParcelableWrapper displayCutout, out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl, - out InsetsState insetsState); + out InsetsState insetsState, out Point outSurfaceSize); /* * Notify the window manager that an application is relaunching and diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index f2c9eb61f86c..09ebd005e7ed 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -436,6 +436,10 @@ public final class ViewRootImpl implements ViewParent, FallbackEventHandler mFallbackEventHandler; Choreographer mChoreographer; + // used in relayout to get SurfaceControl size + // for BLAST adapter surface setup + private final Point mSurfaceSize = new Point(); + final Rect mTempRect; // used in the transaction to not thrash the heap. final Rect mVisRect; // used to retrieve visible rect of focused view. private final Rect mTempBoundsRect = new Rect(); // used to set the size of the bounds surface. @@ -7333,14 +7337,13 @@ public final class ViewRootImpl implements ViewParent, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber, mTmpFrame, mPendingContentInsets, mPendingVisibleInsets, mPendingStableInsets, mPendingBackDropFrame, mPendingDisplayCutout, - mPendingMergedConfiguration, mSurfaceControl, mTempInsets); + mPendingMergedConfiguration, mSurfaceControl, mTempInsets, mSurfaceSize); if (mSurfaceControl.isValid()) { if (!WindowManagerGlobal.USE_BLAST_ADAPTER) { mSurface.copyFrom(mSurfaceControl); } else { - mSurface.transferFrom(getOrCreateBLASTSurface( - (int) (mView.getMeasuredWidth() * appScale + 0.5f), - (int) (mView.getMeasuredHeight() * appScale + 0.5f))); + mSurface.transferFrom(getOrCreateBLASTSurface(mSurfaceSize.x, + mSurfaceSize.y)); } } else { destroySurface(); diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 1312a9b1c158..9f2784889cab 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -18,6 +18,7 @@ package android.view; import android.content.res.Configuration; import android.graphics.PixelFormat; +import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; @@ -159,7 +160,8 @@ public class WindowlessWindowManager implements IWindowSession { Rect outFrame, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, - SurfaceControl outSurfaceControl, InsetsState outInsetsState) { + SurfaceControl outSurfaceControl, InsetsState outInsetsState, + Point outSurfaceSize) { State state = null; synchronized (this) { state = mStateForWindow.get(window.asBinder()); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 35a885f46919..b940cff04713 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -458,9 +458,15 @@ void SkiaPipeline::renderFrameImpl(const SkRect& clip, const SkMatrix& preTransform) { SkAutoCanvasRestore saver(canvas, true); auto clipRestriction = preTransform.mapRect(clip).roundOut(); - canvas->androidFramework_setDeviceClipRestriction(clipRestriction); - canvas->drawAnnotation(SkRect::Make(clipRestriction), "AndroidDeviceClipRestriction", - nullptr); + if (CC_UNLIKELY(mCaptureMode == CaptureMode::SingleFrameSKP + || mCaptureMode == CaptureMode::MultiFrameSKP)) { + canvas->drawAnnotation(SkRect::Make(clipRestriction), "AndroidDeviceClipRestriction", + nullptr); + } else { + // clip drawing to dirty region only when not recording SKP files (which should contain all + // draw ops on every frame) + canvas->androidFramework_setDeviceClipRestriction(clipRestriction); + } canvas->concat(preTransform); // STOPSHIP: Revert, temporary workaround to clear always F16 frame buffer for b/74976293 diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 79b3886338b1..1a0f13943694 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -100,6 +100,8 @@ import java.util.stream.Collectors; * <tr><td>{@link #KEY_AAC_DRC_HEAVY_COMPRESSION}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies whether to use heavy compression.</td></tr> * <tr><td>{@link #KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the maximum number of channels the decoder outputs.</td></tr> * <tr><td>{@link #KEY_AAC_DRC_EFFECT_TYPE}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the MPEG-D DRC effect type to use.</td></tr> + * <tr><td>{@link #KEY_AAC_DRC_OUTPUT_LOUDNESS}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, returns the DRC output loudness.</td></tr> + * <tr><td>{@link #KEY_AAC_DRC_ALBUM_MODE}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the whether MPEG-D DRC Album Mode is active or not.</td></tr> * <tr><td>{@link #KEY_CHANNEL_MASK}</td><td>Integer</td><td>optional, a mask of audio channel assignments</td></tr> * <tr><td>{@link #KEY_ENCODER_DELAY}</td><td>Integer</td><td>optional, the number of frames to trim from the start of the decoded audio stream.</td></tr> * <tr><td>{@link #KEY_ENCODER_PADDING}</td><td>Integer</td><td>optional, the number of frames to trim from the end of the decoded audio stream.</td></tr> @@ -736,6 +738,37 @@ public final class MediaFormat { public static final String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression"; /** + * A key to retrieve the output loudness of a decoded bitstream. + * <p>If loudness normalization is active, the value corresponds to the Target Reference Level + * (see {@link #KEY_AAC_DRC_TARGET_REFERENCE_LEVEL}).<br> + * If loudness normalization is not active, the value corresponds to the loudness metadata + * given in the bitstream. + * <p>The value is retrieved with getInteger() and is given as an integer value between 0 and + * 231. It is calculated as -4 * Output Loudness in LKFS. Therefore, it represents the range of + * 0 to -57.75 LKFS. + * <p>A value of -1 indicates that no loudness metadata is present in the bitstream. + * <p>Loudness metadata can originate from MPEG-4 DRC or MPEG-D DRC. + * <p>This key is only used during decoding. + */ + public static final String KEY_AAC_DRC_OUTPUT_LOUDNESS = "aac-drc-output-loudness"; + + /** + * A key describing the album mode for MPEG-D DRC as defined in ISO/IEC 23003-4. + * <p>The associated value is an integer and can be set to following values: + * <table> + * <tr><th>Value</th><th>Album Mode</th></tr> + * <tr><th>0</th><th>disabled</th></tr> + * <tr><th>1</th><th>enabled</th></tr> + * </table> + * <p>Disabled album mode leads to application of gain sequences for fading in and out, if + * provided in the bitstream. Enabled album mode makes use of dedicated album loudness + * information, if provided in the bitstream. + * <p>The default value is 0 (album mode disabled). + * <p>This key is only used during decoding. + */ + public static final String KEY_AAC_DRC_ALBUM_MODE = "aac-drc-album-mode"; + + /** * A key describing the FLAC compression level to be used (FLAC audio format only). * The associated value is an integer ranging from 0 (fastest, least compression) * to 8 (slowest, most compression). diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java index 7cf5147a9f26..fb30bdec68b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java @@ -121,8 +121,13 @@ public class StatusBarWindowController { apply(mCurrentState); } + private void applyHeight() { + mLpChanged.height = mBarHeight; + } + private void apply(State state) { applyForceStatusBarVisibleFlag(state); + applyHeight(); if (mLp != null && mLp.copyFrom(mLpChanged) != 0) { mWindowManager.updateViewLayout(mStatusBarView, mLp); } diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java index 02c7857f0cfd..5aba013a7fb8 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java +++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java @@ -39,10 +39,10 @@ import android.view.IWindowSessionCallback; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.SurfaceControl; +import android.view.SurfaceControlViewHost; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import android.view.SurfaceControlViewHost; import android.view.WindowlessWindowManager; import com.android.internal.os.IResultReceiver; @@ -238,11 +238,13 @@ public class SystemWindows { long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, - SurfaceControl outSurfaceControl, InsetsState outInsetsState) { + SurfaceControl outSurfaceControl, InsetsState outInsetsState, + Point outSurfaceSize) { int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight, viewVisibility, flags, frameNumber, outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, outStableInsets, - cutout, mergedConfiguration, outSurfaceControl, outInsetsState); + cutout, mergedConfiguration, outSurfaceControl, outInsetsState, + outSurfaceSize); if (res != 0) { return res; } diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java index bda0e3bb39fc..5e10916c4491 100644 --- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java @@ -47,6 +47,7 @@ import android.os.RemoteException; import android.os.SELinux; import android.os.UserHandle; import android.os.WorkSource; +import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -65,14 +66,18 @@ import com.android.server.backup.remote.RemoteCall; import com.android.server.backup.remote.RemoteCallable; import com.android.server.backup.remote.RemoteResult; import com.android.server.backup.transport.TransportClient; +import com.android.server.backup.transport.TransportNotAvailableException; import com.android.server.backup.utils.AppBackupUtils; +import libcore.io.IoUtils; + import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.annotation.Retention; @@ -80,8 +85,10 @@ import java.lang.annotation.RetentionPolicy; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; @@ -169,10 +176,14 @@ import java.util.concurrent.atomic.AtomicInteger; // TODO: Consider having the caller responsible for some clean-up (like resetting state) // TODO: Distinguish between cancel and time-out where possible for logging/monitoring/observing public class KeyValueBackupTask implements BackupRestoreTask, Runnable { + private static final String TAG = "KVBT"; + private static final int THREAD_PRIORITY = Process.THREAD_PRIORITY_BACKGROUND; private static final AtomicInteger THREAD_COUNT = new AtomicInteger(); private static final String BLANK_STATE_FILE_NAME = "blank_state"; private static final String PM_PACKAGE = UserBackupManagerService.PACKAGE_MANAGER_SENTINEL; + private static final String SUCCESS_STATE_SUBDIR = "backing-up"; + @VisibleForTesting static final String NO_DATA_END_SENTINEL = "@end@"; @VisibleForTesting public static final String STAGING_FILE_SUFFIX = ".data"; @VisibleForTesting public static final String NEW_STATE_FILE_SUFFIX = ".new"; @@ -336,6 +347,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { mHasDataToBackup = false; + Set<String> backedUpApps = new HashSet<>(); int status = BackupTransport.TRANSPORT_OK; try { startTask(); @@ -347,13 +359,18 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { } else { backupPackage(packageName); } + setSuccessState(packageName, true); + backedUpApps.add(packageName); } catch (AgentException e) { + setSuccessState(packageName, false); if (e.isTransitory()) { // We try again this package in the next backup pass. mBackupManagerService.dataChangedImpl(packageName); } } } + + informTransportOfUnchangedApps(backedUpApps); } catch (TaskException e) { if (e.isStateCompromised()) { mBackupManagerService.resetBackupState(mStateDirectory); @@ -364,6 +381,185 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { finishTask(status); } + /** + * Tell the transport about all of the packages which have successfully backed up but + * have not informed the framework that they have new data. This allows transports to + * differentiate between packages which are not backing data up due to an error and + * packages which are not backing up data because nothing has changed. + * + * The current implementation involves creating a state file when a backup succeeds, + * on subsequent runs the existence of the file indicates the backup ran successfully + * but there was no data. If a backup fails with an error, or if the package is not + * eligible for backup by the transport any more, the status file is removed and the + * "no data" message will not be sent to the transport until another successful data + * changed backup has succeeded. + * + * @param appsBackedUp The Set of apps backed up during this run so we can exclude them + * from the list of successfully backed up apps that we signal to + * the transport have no data. + */ + private void informTransportOfUnchangedApps(Set<String> appsBackedUp) { + String[] succeedingPackages = getSucceedingPackages(); + if (succeedingPackages == null) { + // Nothing is succeeding, so end early. + return; + } + + int flags = BackupTransport.FLAG_DATA_NOT_CHANGED; + if (mUserInitiated) { + flags |= BackupTransport.FLAG_USER_INITIATED; + } + + boolean noDataPackageEncountered = false; + try { + IBackupTransport transport = + mTransportClient.connectOrThrow("KVBT.informTransportOfEmptyBackups()"); + + for (String packageName : succeedingPackages) { + if (appsBackedUp.contains(packageName)) { + Log.v(TAG, "Skipping package which was backed up this time :" + packageName); + // Skip packages we backed up in this run. + continue; + } + + PackageInfo packageInfo; + try { + packageInfo = mPackageManager.getPackageInfo(packageName, /* flags */ 0); + if (!isEligibleForNoDataCall(packageInfo)) { + // If the package isn't eligible any more we can forget about it and move + // on. + clearStatus(packageName); + continue; + } + } catch (PackageManager.NameNotFoundException e) { + // If the package has been uninstalled we can forget about it and move on. + clearStatus(packageName); + continue; + } + + sendNoDataChangedTo(transport, packageInfo, flags); + noDataPackageEncountered = true; + } + + if (noDataPackageEncountered) { + // If we've notified the transport of an unchanged package we need to + // tell it that it's seen all of the unchanged packages. We do this by + // reporting the end sentinel package as unchanged. + PackageInfo endSentinal = new PackageInfo(); + endSentinal.packageName = NO_DATA_END_SENTINEL; + sendNoDataChangedTo(transport, endSentinal, flags); + } + } catch (TransportNotAvailableException | RemoteException e) { + Log.e(TAG, "Could not inform transport of all unchanged apps", e); + } + } + + /** Determine if a package is eligible to be backed up to the transport */ + private boolean isEligibleForNoDataCall(PackageInfo packageInfo) { + return AppBackupUtils.appIsKeyValueOnly(packageInfo) + && AppBackupUtils.appIsRunningAndEligibleForBackupWithTransport(mTransportClient, + packageInfo.packageName, mPackageManager, mUserId); + } + + /** Send the "no data changed" message to a transport for a specific package */ + private void sendNoDataChangedTo(IBackupTransport transport, PackageInfo packageInfo, int flags) + throws RemoteException { + ParcelFileDescriptor pfd; + try { + pfd = ParcelFileDescriptor.open(mBlankStateFile, MODE_READ_ONLY | MODE_CREATE); + } catch (FileNotFoundException e) { + Log.e(TAG, "Unable to find blank state file, aborting unchanged apps signal."); + return; + } + try { + int result = transport.performBackup(packageInfo, pfd, flags); + if (result == BackupTransport.TRANSPORT_ERROR + || result == BackupTransport.TRANSPORT_NOT_INITIALIZED) { + Log.w( + TAG, + "Aborting informing transport of unchanged apps, transport" + " errored"); + return; + } + + transport.finishBackup(); + } finally { + IoUtils.closeQuietly(pfd); + } + } + + /** Get the list of package names which are marked as having previously succeeded */ + private String[] getSucceedingPackages() { + File stateDirectory = getTopLevelSuccessStateDirectory(/* createIfMissing */ false); + if (stateDirectory == null) { + // getSuccessStateFileFor logs when we can't use the state area + return null; + } + + return stateDirectory.list(); + } + + /** Sets the indicator that a package backup is succeeding */ + private void setSuccessState(String packageName, boolean success) { + File successStateFile = getSuccessStateFileFor(packageName); + if (successStateFile == null) { + // The error will have been logged by getSuccessStateFileFor(). + return; + } + + if (successStateFile.exists() != success) { + // If there's been a change of state + if (!success) { + // Clear the status if we're now failing + clearStatus(packageName, successStateFile); + return; + } + + // For succeeding packages we want the file + try { + if (!successStateFile.createNewFile()) { + Log.w(TAG, "Unable to permanently record success for " + packageName); + } + } catch (IOException e) { + Log.w(TAG, "Unable to permanently record success for " + packageName, e); + } + } + } + + /** Clear the status file for a specific package */ + private void clearStatus(String packageName) { + File successStateFile = getSuccessStateFileFor(packageName); + if (successStateFile == null) { + // The error will have been logged by getSuccessStateFileFor(). + return; + } + clearStatus(packageName, successStateFile); + } + + /** Clear the status file for a package once we have the File representation */ + private void clearStatus(String packageName, File successStateFile) { + if (successStateFile.exists()) { + if (!successStateFile.delete()) { + Log.w(TAG, "Unable to remove status file for " + packageName); + } + } + } + + /** Get the backup state file for a package **/ + private File getSuccessStateFileFor(String packageName) { + File stateDirectory = getTopLevelSuccessStateDirectory(/* createIfMissing */ true); + return stateDirectory == null ? null : new File(stateDirectory, packageName); + } + + /** The top level directory for success state files */ + private File getTopLevelSuccessStateDirectory(boolean createIfMissing) { + File directory = new File(mStateDirectory, SUCCESS_STATE_SUBDIR); + if (!directory.exists() && createIfMissing && !directory.mkdirs()) { + Log.e(TAG, "Unable to create backing-up state directory"); + return null; + } + return directory; + } + /** Returns transport status. */ private int sendDataToTransport(@Nullable PackageInfo packageInfo) throws AgentException, TaskException { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b0369752bdaf..d9fbc85fb6e1 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -363,6 +363,7 @@ import com.android.server.wm.ActivityMetricsLaunchObserver; import com.android.server.wm.ActivityServiceConnectionsHolder; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.ActivityTaskManagerService; +import com.android.server.wm.WindowManagerInternal; import com.android.server.wm.WindowManagerService; import com.android.server.wm.WindowProcessController; @@ -1505,6 +1506,7 @@ public class ActivityManagerService extends IActivityManager.Stub @VisibleForTesting public WindowManagerService mWindowManager; + WindowManagerInternal mWmInternal; @VisibleForTesting public ActivityTaskManagerService mActivityTaskManager; @VisibleForTesting @@ -2085,6 +2087,7 @@ public class ActivityManagerService extends IActivityManager.Stub public void setWindowManager(WindowManagerService wm) { synchronized (this) { mWindowManager = wm; + mWmInternal = LocalServices.getService(WindowManagerInternal.class); mActivityTaskManager.setWindowManager(wm); } } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index cbf058700909..0639db02469d 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -65,8 +65,6 @@ import com.android.internal.app.procstats.ProcessStats; import com.android.internal.os.BatteryStatsImpl; import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.Zygote; -import com.android.server.LocalServices; -import com.android.server.wm.WindowManagerInternal; import com.android.server.wm.WindowProcessController; import com.android.server.wm.WindowProcessListener; @@ -1804,9 +1802,6 @@ class ProcessRecord implements WindowProcessListener { /** current wait for debugger dialog */ private AppWaitingForDebuggerDialog mWaitDialog; - private final WindowManagerInternal mWmInternal = - LocalServices.getService(WindowManagerInternal.class); - boolean hasCrashDialogs() { return mCrashDialogs != null; } @@ -1932,7 +1927,9 @@ class ProcessRecord implements WindowProcessListener { } // If there is no foreground window display, fallback to last used display. if (displayContexts.isEmpty() || lastUsedOnly) { - displayContexts.add(mWmInternal.getTopFocusedDisplayUiContext()); + displayContexts.add(mService.mWmInternal != null + ? mService.mWmInternal.getTopFocusedDisplayUiContext() + : mService.mUiContext); } return displayContexts; } diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java index 2247e54ac5f7..e1ebdf17ef7c 100644 --- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java +++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java @@ -62,7 +62,7 @@ public class NotificationHistoryDatabase { private static final String TAG = "NotiHistoryDatabase"; private static final boolean DEBUG = NotificationManagerService.DBG; - private static final int HISTORY_RETENTION_DAYS = 2; + private static final int HISTORY_RETENTION_DAYS = 1; private static final int HISTORY_RETENTION_MS = 24 * 60 * 60 * 1000; private static final long WRITE_BUFFER_INTERVAL_MS = 1000 * 60 * 20; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 8bc8ff4fb492..0e13e6c8772a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -745,7 +745,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A synchronized (mAtmService.mGlobalLock) { Slog.w(TAG, "Activity stop timeout for " + ActivityRecord.this); if (isInHistory()) { - activityStopped(null /*icicle*/, null /*persistentState*/, null /*description*/); + activityStopped( + null /*icicle*/, null /*persistentState*/, null /*description*/); } } } @@ -1286,17 +1287,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A updateColorTransform(); - final ActivityStack oldStack = (oldTask != null) ? oldTask.getStack() : null; - final ActivityStack newStack = (newTask != null) ? newTask.getStack() : null; - // Inform old stack (if present) of activity removal and new stack (if set) of activity - // addition. - if (oldStack != newStack) { - if (oldStack != null) { - oldStack.onActivityRemovedFromStack(this); - } - if (newStack != null) { - newStack.onActivityAddedToStack(this); - } + if (oldTask != null) { + oldTask.cleanUpActivityReferences(this); + } + if (newTask != null && isState(RESUMED)) { + newTask.setResumedActivity(this, "onParentChanged"); } } @@ -2904,8 +2899,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * Note: Call before {@link #removeFromHistory(String)}. */ void cleanUp(boolean cleanServices, boolean setState) { - final ActivityStack stack = getActivityStack(); - stack.onActivityRemovedFromStack(this); + task.cleanUpActivityReferences(this); deferRelaunchUntilPaused = false; frozenBeforeDestroy = false; @@ -5833,7 +5827,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override boolean isWaitingForTransitionStart() { final DisplayContent dc = getDisplayContent(); - return dc.mAppTransition.isTransitionSet() + return dc != null && dc.mAppTransition.isTransitionSet() && (dc.mOpeningApps.contains(this) || dc.mClosingApps.contains(this) || dc.mChangingApps.contains(this)); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 9e32ea085135..60e0f51ef0a0 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -80,7 +80,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION; @@ -119,7 +118,6 @@ import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT; import static com.android.server.wm.StackProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static java.lang.Integer.MAX_VALUE; @@ -153,6 +151,7 @@ import android.os.Message; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; +import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; import android.util.DisplayMetrics; import android.util.Log; @@ -162,7 +161,6 @@ import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.ITaskOrganizer; -import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import com.android.internal.annotations.GuardedBy; @@ -190,7 +188,7 @@ import java.util.function.Consumer; /** * State and management of a single stack of activities. */ -class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAnimationTarget { +class ActivityStack extends Task implements BoundsAnimationTarget { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM; static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; private static final String TAG_APP = TAG + POSTFIX_APP; @@ -251,33 +249,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn RESTARTING_PROCESS } - final ActivityTaskManagerService mAtmService; - - /** - * When we are in the process of pausing an activity, before starting the - * next one, this variable holds the activity that is currently being paused. - */ - ActivityRecord mPausingActivity = null; - - /** - * This is the last activity that we put into the paused state. This is - * used to determine if we need to do an activity transition while sleeping, - * when we normally hold the top activity paused. - */ - ActivityRecord mLastPausedActivity = null; - - /** - * Activities that specify No History must be removed once the user navigates away from them. - * If the device goes to sleep with such an activity in the paused state then we save it here - * and finish it later if another activity replaces it on wakeup. - */ - ActivityRecord mLastNoHistoryActivity = null; - - /** - * Current activity that is resumed, or null if there is none. - */ - ActivityRecord mResumedActivity = null; - // The topmost Activity passed to convertToTranslucent(). When non-null it means we are // waiting for all Activities in mUndrawnActivitiesBelowTopTranslucent to be removed as they // are drawn. When the last member of mUndrawnActivitiesBelowTopTranslucent is removed the @@ -294,11 +265,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn boolean mConfigWillChange; /** - * When set, will force the stack to report as invisible. - */ - boolean mForceHidden = false; - - /** * Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */ boolean mInResumeTopActivity = false; @@ -311,18 +277,12 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn int mCurrentUser; - /** The attached Display's unique identifier, or -1 if detached */ - private int mDisplayId; - // Id of the previous display the stack was on. - int mPrevDisplayId = INVALID_DISPLAY; - /** Unique identifier */ final int mStackId; /** For comparison with DisplayContent bounds. */ private Rect mTmpRect = new Rect(); private Rect mTmpRect2 = new Rect(); - private Rect mTmpRect3 = new Rect(); /** For Pinned stack controlling. */ private Rect mTmpToBounds = new Rect(); @@ -336,9 +296,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn */ private final Rect mFullyAdjustedImeBounds = new Rect(); - /** ActivityRecords that are exiting, but still on screen for animations. */ - final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>(); - /** Detach this stack from its display when animation completes. */ // TODO: maybe tie this to WindowContainer#removeChild some how... private boolean mDeferRemoval; @@ -367,8 +324,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn Rect mPreAnimationBounds = new Rect(); - private Dimmer mDimmer = new Dimmer(this); - /** * For {@link #prepareSurfaces}. */ @@ -384,10 +339,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn /** List for processing through a set of activities */ private final ArrayList<ActivityRecord> mTmpActivities = new ArrayList<>(); - /** Run all ActivityStacks through this */ - protected final ActivityStackSupervisor mStackSupervisor; - protected final RootWindowContainer mRootWindowContainer; - private boolean mTopActivityOccludesKeyguard; private ActivityRecord mTopDismissingKeyguardActivity; @@ -638,52 +589,68 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } } - ActivityStack(DisplayContent display, int stackId, ActivityStackSupervisor supervisor, - int activityType) { - super(supervisor.mService.mWindowManager); - mStackId = stackId; - mDockedStackMinimizeThickness = - supervisor.mService.mWindowManager.mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.docked_stack_minimize_thickness); - EventLogTags.writeWmStackCreated(stackId); - mStackSupervisor = supervisor; - mAtmService = supervisor.mService; - mRootWindowContainer = mAtmService.mRootWindowContainer; - mHandler = new ActivityStackHandler(supervisor.mLooper); - mRemoteToken = new RemoteToken(this); - mCurrentUser = mAtmService.mAmInternal.getCurrentUserId(); - // Set display id before setting activity and window type to make sure it won't affect - // stacks on a wrong display. - mDisplayId = display.mDisplayId; + ActivityStack(DisplayContent display, int id, ActivityStackSupervisor supervisor, + int activityType, ActivityInfo info, Intent intent) { + this(supervisor.mService, id, info, intent, null /*voiceSession*/, null /*voiceInteractor*/, + null /*taskDescription*/, null /*stack*/); + setActivityType(activityType); } - /** - * This should be called when an activity in a child task changes state. This should only - * be called from - * {@link Task#onActivityStateChanged(ActivityRecord, ActivityState, String)}. - * @param record The {@link ActivityRecord} whose state has changed. - * @param state The new state. - * @param reason The reason for the change. - */ - void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) { - if (record == mResumedActivity && state != RESUMED) { - setResumedActivity(null, reason + " - onActivityStateChanged"); - } - - if (state == RESUMED) { - if (DEBUG_STACK) Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:" - + reason); - setResumedActivity(record, reason + " - onActivityStateChanged"); - if (record == mRootWindowContainer.getTopResumedActivity()) { - mAtmService.setResumedActivityUncheckLocked(record, reason); - } - mStackSupervisor.mRecentTasks.add(record.getTask()); - } + ActivityStack(ActivityTaskManagerService atmService, int id, ActivityInfo info, Intent _intent, + IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, + ActivityManager.TaskDescription _taskDescription, ActivityStack stack) { + this(atmService, id, _intent, null /*_affinityIntent*/, null /*_affinity*/, + null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/, + false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/, + UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/, + null /*_lastDescription*/, System.currentTimeMillis(), + true /*neverRelinquishIdentity*/, + _taskDescription != null ? _taskDescription : new ActivityManager.TaskDescription(), + id, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/, + info.applicationInfo.uid, info.packageName, info.resizeMode, + info.supportsPictureInPicture(), false /*_realActivitySuspended*/, + false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info, + _voiceSession, _voiceInteractor, stack); + } + + ActivityStack(ActivityTaskManagerService atmService, int id, Intent _intent, + Intent _affinityIntent, String _affinity, String _rootAffinity, + ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, + boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid, + String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity, + ActivityManager.TaskDescription _lastTaskDescription, int taskAffiliation, + int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, + String callingPackage, int resizeMode, boolean supportsPictureInPicture, + boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight, + ActivityInfo info, IVoiceInteractionSession _voiceSession, + IVoiceInteractor _voiceInteractor, ActivityStack stack) { + super(atmService, id, _intent, _affinityIntent, _affinity, _rootAffinity, + _realActivity, _origActivity, _rootWasReset, _autoRemoveRecents, _askedCompatMode, + _userId, _effectiveUid, _lastDescription, lastTimeMoved, neverRelinquishIdentity, + _lastTaskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, + callingUid, callingPackage, resizeMode, supportsPictureInPicture, + _realActivitySuspended, userSetupComplete, minWidth, minHeight, info, _voiceSession, + _voiceInteractor, stack); + + mStackId = mTaskId; + mDockedStackMinimizeThickness = mWmService.mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.docked_stack_minimize_thickness); + EventLogTags.writeWmStackCreated(id); + mHandler = new ActivityStackHandler(mStackSupervisor.mLooper); + mCurrentUser = mAtmService.mAmInternal.getCurrentUserId(); } @Override public void onConfigurationChanged(Configuration newParentConfig) { + // Calling Task#onConfigurationChanged() for leaf task since the ops in this method are + // particularly for ActivityStack, like preventing bounds changes when inheriting certain + // windowing mode. + if (!isRootTask()) { + super.onConfigurationChanged(newParentConfig); + return; + } + final int prevWindowingMode = getWindowingMode(); final boolean prevIsAlwaysOnTop = isAlwaysOnTop(); final int prevRotation = getWindowConfiguration().getRotation(); @@ -801,10 +768,16 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn @Override public void setWindowingMode(int windowingMode) { + // Calling Task#setWindowingMode() for leaf task since this is the a specialization of + // {@link #setWindowingMode(int)} for ActivityStack. + if (!isRootTask()) { + super.setWindowingMode(windowingMode); + return; + } + setWindowingMode(windowingMode, false /* animate */, false /* showRecents */, false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */, false /* creating */); - windowingMode = getWindowingMode(); /* * Different windowing modes may be managed by different task organizers. If @@ -893,7 +866,8 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn // Looks like we can't launch in split screen mode or the stack we are launching // doesn't support split-screen mode, go ahead an dismiss split-screen and display a // warning toast about it. - mAtmService.getTaskChangeNotificationController().notifyActivityDismissingDockedStack(); + mAtmService.getTaskChangeNotificationController() + .notifyActivityDismissingDockedStack(); final ActivityStack primarySplitStack = display.getSplitScreenPrimaryStack(); primarySplitStack.setWindowingModeInSurfaceTransaction(WINDOWING_MODE_UNDEFINED, false /* animate */, false /* showRecents */, @@ -972,7 +946,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn false /* preserveWindows */, true /* deferResume */); } } finally { - if (showRecents && !alreadyInSplitScreenMode && mDisplayId == DEFAULT_DISPLAY + if (showRecents && !alreadyInSplitScreenMode && isOnHomeDisplay() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // Make sure recents stack exist when creating a dock stack as it normally needs to // be on the other side of the docked stack and we make visibility decisions based @@ -1029,10 +1003,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn return getDisplayContent(); } - int getDisplayId() { - return mDisplayId; - } - /** * Defers updating the bounds of the stack. If the stack was resized/repositioned while * deferring, the bounds will update in {@link #continueUpdateBounds()}. @@ -1138,10 +1108,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning(); } - ActivityRecord getTopNonFinishingActivity() { - return getTopActivity(false /*includeFinishing*/, true /*includeOverlays*/); - } - ActivityRecord isInStackLocked(IBinder token) { final ActivityRecord r = ActivityRecord.forTokenLocked(token); return isInStackLocked(r); @@ -1172,11 +1138,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } final boolean isOnHomeDisplay() { - return mDisplayId == DEFAULT_DISPLAY; - } - - private boolean returnsToHomeStack() { - return !inMultiWindowMode() && hasChild() && getBottomMostTask().returnsToHomeStack(); + return getDisplayId() == DEFAULT_DISPLAY; } void moveToFront(String reason) { @@ -1280,11 +1242,11 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn super.switchUser(userId); forAllTasks((t) -> { - if (t.mWmService.isCurrentProfile(t.mUserId) || t.showForAllUsers()) { + if (t.showToCurrentUser()) { mChildren.remove(t); mChildren.add(t); } - }); + }, true /* traverseTopToBottom */, this); } void minimalResumeActivityLocked(ActivityRecord r) { @@ -1609,45 +1571,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS); } - /** - * Returns true if the stack is translucent and can have other contents visible behind it if - * needed. A stack is considered translucent if it don't contain a visible or - * starting (about to be visible) activity that is fullscreen (opaque). - * @param starting The currently starting activity or null if there is none. - */ - @VisibleForTesting - boolean isStackTranslucent(ActivityRecord starting) { - if (!isAttached() || mForceHidden) { - return true; - } - final PooledPredicate p = PooledLambda.obtainPredicate(ActivityStack::isOpaqueActivity, - PooledLambda.__(ActivityRecord.class), starting); - final ActivityRecord opaque = getActivity(p); - p.recycle(); - return opaque == null; - } - - private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) { - if (r.finishing) { - // We don't factor in finishing activities when determining translucency since - // they will be gone soon. - return false; - } - - if (!r.visibleIgnoringKeyguard && r != starting) { - // Also ignore invisible activities that are not the currently starting - // activity (about to be visible). - return false; - } - - if (r.occludesParent() || r.hasWallpaper) { - // Stack isn't translucent if it has at least one fullscreen activity - // that is visible. - return true; - } - return false; - } - boolean isTopStackOnDisplay() { final DisplayContent display = getDisplay(); return display != null && display.isTopStack(this); @@ -1667,15 +1590,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn return topActivity != null && topActivity.mVisibleRequested; } - /** - * Indicate whether the first task in this stack is controlled by a TaskOrganizer. We aren't - * expecting to use the TaskOrganizer in multiple task per stack scenarios so checking - * the first one is ok. - */ - boolean isControlledByTaskOrganizer() { - return getChildCount() > 0 && getTopMostTask().mTaskOrganizer != null; - } - private static void transferSingleTaskToOrganizer(Task tr, ITaskOrganizer organizer) { tr.setTaskOrganizer(organizer); } @@ -1690,7 +1604,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn final PooledConsumer c = PooledLambda.obtainConsumer( ActivityStack::transferSingleTaskToOrganizer, PooledLambda.__(Task.class), organizer); - forAllTasks(c); + forAllTasks(c, true /* traverseTopToBottom */, this); c.recycle(); } @@ -1699,6 +1613,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn * * @param starting The currently starting activity or null if there is none. */ + @Override boolean shouldBeVisible(ActivityRecord starting) { return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE; } @@ -1756,7 +1671,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn break; } } - if (other.isStackTranslucent(starting)) { + if (other.isTranslucent(starting)) { // Can be visible behind a translucent fullscreen stack. gotTranslucentFullscreen = true; continue; @@ -1765,7 +1680,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !gotOpaqueSplitScreenPrimary) { gotSplitScreenStack = true; - gotTranslucentSplitScreenPrimary = other.isStackTranslucent(starting); + gotTranslucentSplitScreenPrimary = other.isTranslucent(starting); gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary; if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && gotOpaqueSplitScreenPrimary) { @@ -1775,7 +1690,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY && !gotOpaqueSplitScreenSecondary) { gotSplitScreenStack = true; - gotTranslucentSplitScreenSecondary = other.isStackTranslucent(starting); + gotTranslucentSplitScreenSecondary = other.isTranslucent(starting); gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary; if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY && gotOpaqueSplitScreenSecondary) { @@ -1876,13 +1791,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn return inPinnedWindowingMode(); } - @Override - public boolean supportsSplitScreenWindowingMode() { - final Task topTask = getTopMostTask(); - return super.supportsSplitScreenWindowingMode() - && (topTask == null || topTask.supportsSplitScreenWindowingMode()); - } - + // TODO(NOW!) /** * Returns {@code true} if this is the top-most split-screen-primary or * split-screen-secondary stack, {@code false} otherwise. @@ -1918,7 +1827,9 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn * @return true if {@param r} is visible taken Keyguard state into account, false otherwise */ boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible, boolean isTop) { - final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY; + int displayId = getDisplayId(); + if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY; + final boolean keyguardOrAodShowing = mStackSupervisor.getKeyguardController() .isKeyguardOrAodShowing(displayId); final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked(); @@ -2084,24 +1995,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn return result; } - /** - * Returns the currently resumed activity. - */ - protected ActivityRecord getResumedActivity() { - return mResumedActivity; - } - - private void setResumedActivity(ActivityRecord r, String reason) { - if (mResumedActivity == r) { - return; - } - - if (DEBUG_STACK) Slog.d(TAG_STACK, "setResumedActivity stack:" + this + " + from: " - + mResumedActivity + " to:" + r + " reason:" + reason); - mResumedActivity = r; - mStackSupervisor.updateTopResumedActivityIfNeeded(); - } - @GuardedBy("mService") private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { if (!mAtmService.isBooting() && !mAtmService.isBooted()) { @@ -2412,7 +2305,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn // result of invisible window resize. // TODO: Remove this once visibilities are set correctly immediately when // starting an activity. - notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, mDisplayId, + notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(), true /* markFrozenIfConfigChanged */, false /* deferResume */); } @@ -2553,7 +2446,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn ActivityOptions.abort(options); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeNextFocusableActivityWhenStackIsEmpty: " + reason + ", go home"); - return mRootWindowContainer.resumeHomeActivity(prev, reason, mDisplayId); + return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayId()); } void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity, @@ -2827,7 +2720,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn void finishVoiceTask(IVoiceInteractionSession session) { final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::finishIfVoiceTask, PooledLambda.__(Task.class), session.asBinder()); - forAllTasks(c); + forAllTasks(c, true /* traverseTopToBottom */, this); c.recycle(); } @@ -3020,29 +2913,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn return foundParentInTask; } - /** - * Remove any state associated with the {@link ActivityRecord}. This should be called whenever - * an activity moves away from the stack. - */ - void onActivityRemovedFromStack(ActivityRecord r) { - r.removeTimeouts(); - - mExitingActivities.remove(r); - - if (mResumedActivity != null && mResumedActivity == r) { - setResumedActivity(null, "onActivityRemovedFromStack"); - } - if (mPausingActivity != null && mPausingActivity == r) { - mPausingActivity = null; - } - } - - void onActivityAddedToStack(ActivityRecord r) { - if (r.isState(RESUMED)) { - setResumedActivity(r, "onActivityAddedToStack"); - } - } - void removeLaunchTickMessages() { forAllActivities(ActivityRecord::removeLaunchTickRunnable); } @@ -3141,7 +3011,8 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn mRootWindowContainer.resumeFocusedStacksTopActivities(); } EventLogTags.writeWmTaskToFront(tr.mUserId, tr.mTaskId); - mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.getTaskInfo()); + mAtmService.getTaskChangeNotificationController() + .notifyTaskMovedToFront(tr.getTaskInfo()); } finally { getDisplay().continueUpdateImeTarget(); } @@ -3239,7 +3110,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn final PooledConsumer c = PooledLambda.obtainConsumer( ActivityStack::processTaskResizeBounds, PooledLambda.__(Task.class), taskBounds, tempTaskInsetBounds); - forAllTasks(c); + forAllTasks(c, true /* traverseTopToBottom */, this); c.recycle(); setBounds(bounds); @@ -3276,7 +3147,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskBounds, PooledLambda.__(Task.class), bounds); - forAllTasks(c); + forAllTasks(c, true /* traverseTopToBottom */, this); c.recycle(); } @@ -3292,7 +3163,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskDisplayedBounds, PooledLambda.__(Task.class), bounds); - forAllTasks(c); + forAllTasks(c, true /* traverseTopToBottom */, this); c.recycle(); } @@ -3384,7 +3255,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, String dumpPackage, boolean needSep) { - if (!hasChild()) { return false; } @@ -3403,11 +3273,11 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn final ArrayList<ActivityRecord> activities = new ArrayList<>(); // Add activities by traversing the hierarchy from bottom to top, since activities // are dumped in reverse order in {@link ActivityStackSupervisor#dumpHistoryList()}. - forAllActivities((Consumer<ActivityRecord>) activities::add, + task.forAllActivities((Consumer<ActivityRecord>) activities::add, false /* traverseTopToBottom */); dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient, dumpPackage, false, null, task); - }); + }, true /* traverseTopToBottom */, this); return true; } @@ -3458,49 +3328,9 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } } - /** - * Removes the input task from this stack. - * - * @param child to remove. - * @param reason for removal. - */ - void removeChild(WindowContainer child, String reason) { - if (!mChildren.contains(child)) { - // Not really in this stack anymore... - return; - } - - final DisplayContent display = getDisplay(); - if (DEBUG_TASK_MOVEMENT) { - Slog.d(TAG_WM, "removeChild: task=" + child + " reason=" + reason); - } - - super.removeChild(child); - - EventLogTags.writeWmRemoveTask(((Task) child).mTaskId, mStackId); - - if (display.isSingleTaskInstance()) { - mAtmService.notifySingleTaskDisplayEmpty(display.mDisplayId); - } - - display.mDisplayContent.setLayoutNeeded(); - - if (!hasChild()) { - // Stack is now empty... - removeIfPossible(); - } - } - - @Override - void removeChild(WindowContainer child) { - removeChild(child, "removeChild"); - } - - Task createTask(int taskId, ActivityInfo info, Intent intent, - IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, - boolean toTop) { - return createTask(taskId, info, intent, voiceSession, voiceInteractor, toTop, - null /*activity*/, null /*source*/, null /*options*/); + Task createTask(int taskId, ActivityInfo info, Intent intent, boolean toTop) { + return createTask(taskId, info, intent, null /*voiceSession*/, null /*voiceInteractor*/, + toTop, null /*activity*/, null /*source*/, null /*options*/); } Task createTask(int taskId, ActivityInfo info, Intent intent, @@ -3511,7 +3341,8 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn mAtmService, taskId, info, intent, voiceSession, voiceInteractor, this); // add the task to stack first, mTaskPositioner might need the stack association addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); - final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY; + int displayId = getDisplayId(); + if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY; final boolean isLockscreenShown = mAtmService.mStackSupervisor.getKeyguardController() .isKeyguardOrAodShowing(displayId); if (!mStackSupervisor.getLaunchParamsController() @@ -3522,14 +3353,25 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn return task; } - void addChild(final Task task, final boolean toTop, boolean showForAllUsers) { + void addChild(WindowContainer child, final boolean toTop, boolean showForAllUsers) { if (isSingleTaskInstance() && hasChild()) { throw new IllegalStateException("Can only have one child on stack=" + this); } - // We only want to move the parents to the parents if we are creating this task at the - // top of its stack. - addChild(task, toTop ? MAX_VALUE : 0, showForAllUsers, toTop /*moveParents*/); + Task task = child.asTask(); + try { + + if (task != null) { + task.setForceShowForAllUsers(showForAllUsers); + } + // We only want to move the parents to the parents if we are creating this task at the + // top of its stack. + addChild(child, toTop ? MAX_VALUE : 0, toTop /*moveParents*/); + } finally { + if (task != null) { + task.setForceShowForAllUsers(false); + } + } } void positionChildAt(Task task, int position) { @@ -3747,16 +3589,12 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn final PooledConsumer c = PooledLambda.obtainConsumer( ActivityStackSupervisor::updatePictureInPictureMode, mStackSupervisor, PooledLambda.__(Task.class), targetStackBounds, forceUpdate); - forAllTasks(c); + forAllTasks(c, true /* traverseTopToBottom */, this); c.recycle(); } - public int getStackId() { - return mStackId; - } - void prepareFreezingTaskBounds() { - forAllTasks(Task::prepareFreezingBounds); + forAllTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */, this); } /** @@ -3788,7 +3626,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn final PooledConsumer c = PooledLambda.obtainConsumer(Task::alignToAdjustedBounds, PooledLambda.__(Task.class), adjusted ? mAdjustedBounds : getRawBounds(), insetBounds, alignBottom); - forAllTasks(c); + forAllTasks(c, true /* traverseTopToBottom */, this); c.recycle(); } @@ -3798,7 +3636,13 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn @Override public int setBounds(Rect bounds) { - return setBounds(getRequestedOverrideBounds(), bounds); + // Calling Task#setBounds() for leaf task since this is the a specialization of + // {@link #setBounds(int)} for ActivityStack. + if (!isRootTask()) { + return super.setBounds(bounds); + } else { + return setBounds(getRequestedOverrideBounds(), bounds); + } } private int setBounds(Rect existing, Rect bounds) { @@ -4038,30 +3882,15 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn * Put a Task in this stack. Used for adding only. * When task is added to top of the stack, the entire branch of the hierarchy (including stack * and display) will be brought to top. - * @param task The task to add. + * @param child The child to add. * @param position Target position to add the task to. - * @param showForAllUsers Whether to show the task regardless of the current user. */ - private void addChild(Task task, int position, boolean showForAllUsers, boolean moveParents) { - try { - // Force show for all user so task can be position correctly based on which user is - // active. We clear the force show below. - task.setForceShowForAllUsers(showForAllUsers); - // Add child task. - addChild(task, null); - - // Move child to a proper position, as some restriction for position might apply. - positionChildAt(position, task, moveParents /* includingParents */); - - } finally { - task.setForceShowForAllUsers(false); - } - } + private void addChild(WindowContainer child, int position, boolean moveParents) { + // Add child task. + addChild(child, null); - @Override - void addChild(WindowContainer child, int position) { - final Task task = (Task) child; - addChild(task, position, task.showForAllUsers(), false /* includingParents */); + // Move child to a proper position, as some restriction for position might apply. + positionChildAt(position, child, moveParents /* includingParents */); } void positionChildAtTop(Task child) { @@ -4099,29 +3928,18 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } @Override - void positionChildAt(int position, WindowContainer child, boolean includingParents) { - final Task task = (Task) child; - final int targetPosition = findPositionForTask(task, position); - super.positionChildAt(targetPosition, child, includingParents); - - // Log positioning. - if (DEBUG_TASK_MOVEMENT) { - Slog.d(TAG_WM, "positionTask: task=" + this + " position=" + position); - } - - final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0; - EventLogTags.writeWmTaskMoved(task.mTaskId, toTop, targetPosition); - } - - @Override void onChildPositionChanged(WindowContainer child) { if (!mChildren.contains(child)) { return; } - final Task task = (Task) child; - final boolean isTop = getTopChild() == task; - task.updateTaskMovement(isTop); + final boolean isTop = getTopChild() == child; + + final Task task = child.asTask(); + if (task != null) { + task.updateTaskMovement(isTop); + } + if (isTop) { final DisplayContent displayContent = getDisplayContent(); displayContent.layoutAndAssignWindowLayersIfNeeded(); @@ -4129,34 +3947,17 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } @Override - protected void onParentChanged( - ConfigurationContainer newParent, ConfigurationContainer oldParent) { + void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { final DisplayContent display = newParent != null ? ((WindowContainer) newParent).getDisplayContent() : null; final DisplayContent oldDisplay = oldParent != null ? ((WindowContainer) oldParent).getDisplayContent() : null; - mDisplayId = (display != null) ? display.mDisplayId : INVALID_DISPLAY; - mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY; - - if (display != null) { - // Rotations are relative to the display. This means if there are 2 displays rotated - // differently (eg. 2 monitors with one landscape and one portrait), moving a stack - // from one to the other could look like a rotation change. To prevent this - // apparent rotation change (and corresponding bounds rotation), pretend like our - // current rotation is already the same as the new display. - // Note, if ActivityStack or related logic ever gets nested, this logic will need - // to move to onConfigurationChanged. - getConfiguration().windowConfiguration.setRotation( - display.getWindowConfiguration().getRotation()); - } super.onParentChanged(newParent, oldParent); - if (getParent() == null && mDisplayContent != null) { - EventLogTags.writeWmStackRemoved(mStackId); - mDisplayContent = null; - mWmService.mWindowPlacerLocked.requestTraversal(); - } - if (display != null && inSplitScreenPrimaryWindowingMode()) { + + if (display != null && inSplitScreenPrimaryWindowingMode() + // only do this for the base stack + && !newParent.inSplitScreenPrimaryWindowingMode()) { // If we created a docked stack we want to resize it so it resizes all other stacks // in the system. getStackDockedModeBounds(null /* dockedBounds */, null /* currentTempTaskBounds */, @@ -4164,7 +3965,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn mStackSupervisor.resizeDockedStackLocked(getRequestedOverrideBounds(), mTmpRect, mTmpRect2, null, null, PRESERVE_WINDOWS); } - mRootWindowContainer.updateUIDsPresentOnDisplay(); // Resume next focusable stack after reparenting to another display if we aren't removing // the prevous display. @@ -4178,68 +3978,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn newParent.moveStackToDisplay(this, onTop); } - // TODO: We should really have users as a window container in the hierarchy so that we don't - // have to do complicated things like we are doing in this method. - int findPositionForTask(Task task, int targetPosition) { - final boolean canShowTask = task.showToCurrentUser(); - - final int stackSize = mChildren.size(); - int minPosition = 0; - int maxPosition = stackSize - 1; - - if (canShowTask) { - minPosition = computeMinPosition(minPosition, stackSize); - } else { - maxPosition = computeMaxPosition(maxPosition); - } - - // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid. - if (targetPosition == POSITION_BOTTOM && minPosition == 0) { - return POSITION_BOTTOM; - } else if (targetPosition == POSITION_TOP && maxPosition == (stackSize - 1)) { - return POSITION_TOP; - } - // Reset position based on minimum/maximum possible positions. - return Math.min(Math.max(targetPosition, minPosition), maxPosition); - } - - /** Calculate the minimum possible position for a task that can be shown to the user. - * The minimum position will be above all other tasks that can't be shown. - * @param minPosition The minimum position the caller is suggesting. - * We will start adjusting up from here. - * @param size The size of the current task list. - */ - // TODO(task-hierarchy): Move user to their own window container. - private int computeMinPosition(int minPosition, int size) { - while (minPosition < size) { - final Task tmpTask = (Task) mChildren.get(minPosition); - final boolean canShowTmpTask = tmpTask.showToCurrentUser(); - if (canShowTmpTask) { - break; - } - minPosition++; - } - return minPosition; - } - - /** Calculate the maximum possible position for a task that can't be shown to the user. - * The maximum position will be below all other tasks that can be shown. - * @param maxPosition The maximum position the caller is suggesting. - * We will start adjusting down from here. - */ - // TODO(task-hierarchy): Move user to their own window container. - private int computeMaxPosition(int maxPosition) { - while (maxPosition > 0) { - final Task tmpTask = (Task) mChildren.get(maxPosition); - final boolean canShowTmpTask = tmpTask.showToCurrentUser(); - if (!canShowTmpTask) { - break; - } - maxPosition--; - } - return maxPosition; - } - private void updateSurfaceBounds() { updateSurfaceSize(getPendingTransaction()); updateSurfacePosition(); @@ -4456,15 +4194,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn false /* deferResume */); } - @Override - void removeIfPossible() { - if (isAnimating(TRANSITION | CHILDREN)) { - mDeferRemoval = true; - return; - } - removeImmediately(); - } - /** * Adjusts the stack bounds if the IME is visible. * @@ -4568,12 +4297,14 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn t.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER); t.setWaitingForDrawnIfResizingChanged(); } - }); + }, true /* traverseTopToBottom */, this); } /** Resets the resizing state of all windows. */ void endImeAdjustAnimation() { - forAllTasks((t) -> { t.setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER); }); + forAllTasks((t) -> { + t.setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER); + }, true /* traverseTopToBottom */, this); } private int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) { @@ -4751,14 +4482,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn return mMinimizeAmount != 0f; } - /** - * @return {@code true} if we have a {@link Task} that is animating (currently only used for the - * recents animation); {@code false} otherwise. - */ - boolean isTaskAnimating() { - return getTask(Task::isTaskAnimating) != null; - } - @Override void dump(PrintWriter pw, String prefix, boolean dumpAll) { pw.println(prefix + "mStackId=" + mStackId); @@ -4792,11 +4515,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn mAnimatingActivityRegistry.dump(pw, "AnimatingApps:", prefix); } - @Override - boolean fillsParent() { - return matchParentBounds(); - } - String getName() { return toShortString(); } @@ -4996,7 +4714,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn /** Called immediately prior to resizing the tasks at the end of the pinned stack animation. */ void onPipAnimationEndResize() { mBoundsAnimating = false; - forAllTasks(Task::clearPreserveNonFloatingState, false); + forAllTasks(Task::clearPreserveNonFloatingState, false /* traverseTopToBottom */, this); mWmService.requestTraversal(); } @@ -5096,24 +4814,6 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } @Override - Dimmer getDimmer() { - return mDimmer; - } - - @Override - void prepareSurfaces() { - mDimmer.resetDimStates(); - super.prepareSurfaces(); - getDimBounds(mTmpDimBoundsRect); - - // Bounds need to be relative, as the dim layer is a child. - mTmpDimBoundsRect.offsetTo(0, 0); - if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) { - scheduleAnimation(); - } - } - - @Override public boolean setPinnedStackAlpha(float alpha) { // Hold the lock since this is called from the BoundsAnimator running on the UiThread synchronized (mWmService.mGlobalLock) { @@ -5132,49 +4832,10 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn return mDisplayContent.getDisplayInfo(); } - void dim(float alpha) { - mDimmer.dimAbove(getPendingTransaction(), alpha); - scheduleAnimation(); - } - - void stopDimming() { - mDimmer.stopDim(getPendingTransaction()); - scheduleAnimation(); - } - AnimatingActivityRegistry getAnimatingActivityRegistry() { return mAnimatingActivityRegistry; } - @Override - void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, - Rect outSurfaceInsets) { - final Task task = getTopMostTask(); - if (task != null) { - task.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); - } else { - super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); - } - } - - @Override - RemoteAnimationTarget createRemoteAnimationTarget( - RemoteAnimationController.RemoteAnimationRecord record) { - final Task task = getTopMostTask(); - return task != null ? task.createRemoteAnimationTarget(record) : null; - } - - @Override - public String toString() { - return "ActivityStack{" + Integer.toHexString(System.identityHashCode(this)) - + " stackId=" + mStackId + " type=" + activityTypeToString(getActivityType()) - + " mode=" + windowingModeToString(getWindowingMode()) - + " visible=" + shouldBeVisible(null /* starting */) - + " translucent=" + isStackTranslucent(null /* starting */) - + ", " - + getChildCount() + " tasks}"; - } - void executeAppTransition(ActivityOptions options) { getDisplay().mDisplayContent.executeAppTransition(); ActivityOptions.abort(options); @@ -5197,6 +4858,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn return shouldSleepActivities() || mAtmService.mShuttingDown; } + @Override public void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { final long token = proto.start(fieldId); @@ -5204,12 +4866,12 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn proto.write(com.android.server.am.ActivityStackProto.ID, mStackId); forAllTasks((t) -> { - t.dumpDebug(proto, com.android.server.am.ActivityStackProto.TASKS, logLevel); - }); + t.dumpDebugInner(proto, com.android.server.am.ActivityStackProto.TASKS, logLevel); + }, true /* traverseTopToBottom */, this); if (mResumedActivity != null) { mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); } - proto.write(DISPLAY_ID, mDisplayId); + proto.write(DISPLAY_ID, getDisplayId()); if (!matchParentBounds()) { final Rect bounds = getRequestedOverrideBounds(); bounds.dumpDebug(proto, com.android.server.am.ActivityStackProto.BOUNDS); @@ -5230,7 +4892,9 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn final long token = proto.start(fieldId); super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); proto.write(StackProto.ID, mStackId); - forAllTasks((t) -> { t.dumpDebugInnerTaskOnly(proto, StackProto.TASKS, logLevel); }); + forAllTasks((t) -> { + t.dumpDebugInnerTaskOnly(proto, StackProto.TASKS, logLevel); + }, true /* traverseTopToBottom */, this); proto.write(FILLS_PARENT, matchParentBounds()); getRawBounds().dumpDebug(proto, StackProto.BOUNDS); proto.write(DEFER_REMOVAL, mDeferRemoval); diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 8ef01e3f4776..f2ce7e86bc3b 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -419,7 +419,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { final PooledConsumer c = PooledLambda.obtainConsumer( MoveTaskToFullscreenHelper::processTask, this, PooledLambda.__(Task.class)); - fromStack.forAllTasks(c, false); + fromStack.forAllTasks(c, false /* traverseTopToBottom */, fromStack); c.recycle(); mToDisplay = null; mTopTask = null; @@ -1724,7 +1724,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } else { final PooledConsumer c = PooledLambda.obtainConsumer( ActivityStackSupervisor::processRemoveTask, this, PooledLambda.__(Task.class)); - stack.forAllTasks(c); + stack.forAllTasks(c, true /* traverseTopToBottom */, stack); c.recycle(); } } @@ -1849,14 +1849,14 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { boolean restoreRecentTaskLocked(Task task, ActivityOptions aOptions, boolean onTop) { final ActivityStack stack = mRootWindowContainer.getLaunchStack(null, aOptions, task, onTop); - final ActivityStack currentStack = task.getStack(); + final WindowContainer parent = task.getParent(); - if (currentStack == stack) { + if (parent == stack) { // Nothing else to do since it is already restored in the right stack. return true; } - if (currentStack != null) { + if (parent != null) { // Task has already been restored once. Just re-parent it to the new stack. task.reparent(stack, POSITION_TOP, true /*moveParents*/, "restoreRecentTaskLocked"); return true; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 47e8b87dcf08..8491bc2c4756 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -306,7 +306,7 @@ import java.util.Set; */ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityTaskManagerService" : TAG_ATM; - private static final String TAG_STACK = TAG + POSTFIX_STACK; + static final String TAG_STACK = TAG + POSTFIX_STACK; static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE; private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; @@ -2057,8 +2057,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public int getDisplayId(IBinder activityToken) throws RemoteException { synchronized (mGlobalLock) { final ActivityStack stack = ActivityRecord.getStackLocked(activityToken); - if (stack != null && stack.getDisplayId() != INVALID_DISPLAY) { - return stack.getDisplayId(); + if (stack != null) { + final int displayId = stack.getDisplayId(); + return displayId != INVALID_DISPLAY ? displayId : DEFAULT_DISPLAY; } return DEFAULT_DISPLAY; } @@ -3216,8 +3217,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final ActivityStack stack = r.getActivityStack(); final Task task = stack.createTask( - mStackSupervisor.getNextTaskIdForUser(r.mUserId), ainfo, intent, - null /* voiceSession */, null /* voiceInteractor */, !ON_TOP); + mStackSupervisor.getNextTaskIdForUser(r.mUserId), ainfo, intent, !ON_TOP); if (!mRecentTasks.addToBottom(task)) { // The app has too many tasks already and we can't add any more stack.removeChild(task, "addAppTask"); @@ -4385,7 +4385,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (params.hasSetAspectRatio() && !mWindowManager.isValidPictureInPictureAspectRatio( - r.getDisplayId(), params.getAspectRatio())) { + r.getDisplay(), params.getAspectRatio())) { final float minAspectRatio = mContext.getResources().getFloat( com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio); final float maxAspectRatio = mContext.getResources().getFloat( diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 32802eed94f4..0d19ef723236 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -69,7 +69,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFI import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; -import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; @@ -167,8 +166,10 @@ import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.WindowConfiguration; import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.ScreenOrientation; +import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; @@ -306,8 +307,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // on the IME target. We mainly have this container grouping so we can keep track of all the IME // window containers together and move them in-sync if/when needed. We use a subclass of // WindowContainer which is omitted from screen magnification, as the IME is never magnified. - private final NonAppWindowContainers mImeWindowsContainers = - new NonAppWindowContainers("mImeWindowsContainers", mWmService); + // TODO(display-area): is "no magnification" in the comment still true? + private final ImeContainer mImeWindowsContainers = new ImeContainer(mWmService); private WindowState mTmpWindow; private WindowState mTmpWindow2; @@ -2026,6 +2027,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mTaskStackContainers.getVisibleTasks(); } + SurfaceControl getSplitScreenDividerAnchor() { + return mTaskStackContainers.getSplitScreenDividerAnchor(); + } + void onStackWindowingModeChanged(ActivityStack stack) { mTaskStackContainers.onStackWindowingModeChanged(stack); } @@ -2112,7 +2117,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } boolean forAllImeWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { - return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom); + return mImeWindowsContainers.forAllWindowForce(callback, traverseTopToBottom); } /** @@ -2370,11 +2375,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo throw new UnsupportedOperationException("See DisplayChildWindowContainer"); } + void positionDisplayAt(int position, boolean includingParents) { + getParent().positionChildAt(position, this, includingParents); + } + @Override void positionChildAt(int position, DisplayChildWindowContainer child, boolean includingParents) { // Children of the display are statically ordered, so the real intention here is to perform // the operation on the display and not the static direct children. - getParent().positionChildAt(position, this, includingParents); + positionDisplayAt(position, includingParents); } void positionStackAt(int position, ActivityStack child, boolean includingParents) { @@ -4243,7 +4252,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo ArrayList<Task> getVisibleTasks() { final ArrayList<Task> visibleTasks = new ArrayList<>(); forAllTasks(task -> { - if (task.isVisible()) { + if (!task.isRootTask() && task.isVisible()) { visibleTasks.add(task); } }); @@ -4262,36 +4271,48 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private void addStackReferenceIfNeeded(ActivityStack stack) { if (stack.isActivityTypeHome()) { if (mHomeStack != null) { - throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack=" - + mHomeStack + " already exist on display=" + this + " stack=" + stack); - + if (!stack.isDescendantOf(mHomeStack)) { + throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack=" + + mHomeStack + " already exist on display=" + this + + " stack=" + stack); + } + } else { + mHomeStack = stack; } - mHomeStack = stack; } else if (stack.isActivityTypeRecents()) { if (mRecentsStack != null && mRecentsStack != stack) { - throw new IllegalArgumentException( - "addStackReferenceIfNeeded: recents stack=" + mRecentsStack - + " already exist on display=" + this + " stack=" + stack); + if (!stack.isDescendantOf(mRecentsStack)) { + throw new IllegalArgumentException( + "addStackReferenceIfNeeded: recents stack=" + mRecentsStack + + " already exist on display=" + this + " stack=" + stack); + } + } else { + mRecentsStack = stack; } - mRecentsStack = stack; } final int windowingMode = stack.getWindowingMode(); if (windowingMode == WINDOWING_MODE_PINNED) { if (mPinnedStack != null) { - throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack=" - + mPinnedStack + " already exist on display=" + this - + " stack=" + stack); + if (!stack.isDescendantOf(mPinnedStack)) { + throw new IllegalArgumentException( + "addStackReferenceIfNeeded: pinned stack=" + mPinnedStack + + " already exist on display=" + this + " stack=" + stack); + } + } else { + mPinnedStack = stack; } - mPinnedStack = stack; } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { if (mSplitScreenPrimaryStack != null) { - throw new IllegalArgumentException("addStackReferenceIfNeeded:" - + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack - + " already exist on display=" + this + " stack=" + stack); + if (!stack.isDescendantOf(mSplitScreenPrimaryStack)) { + throw new IllegalArgumentException("addStackReferenceIfNeeded:" + + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack + + " already exist on display=" + this + " stack=" + stack); + } + } else { + mSplitScreenPrimaryStack = stack; + mDisplayContent.onSplitScreenModeActivated(); + mDividerControllerLocked.notifyDockedStackExistsChanged(true); } - mSplitScreenPrimaryStack = stack; - mDisplayContent.onSplitScreenModeActivated(); - mDividerControllerLocked.notifyDockedStackExistsChanged(true); } } @@ -4340,8 +4361,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo @Override void positionChildAt(int position, ActivityStack child, boolean includingParents) { - if (child.getWindowConfiguration().isAlwaysOnTop() - && position != POSITION_TOP && position != mChildren.size()) { + final boolean moveToTop = (position == POSITION_TOP || position == getChildCount()); + final boolean moveToBottom = (position == POSITION_BOTTOM || position == 0); + if (child.getWindowConfiguration().isAlwaysOnTop() && !moveToTop) { // This stack is always-on-top, override the default behavior. Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + this + " to bottom"); @@ -4357,18 +4379,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo includingParents = false; } final int targetPosition = findPositionForStack(position, child, false /* adding */); - super.positionChildAt(targetPosition, child, includingParents); - - if (includingParents) { - // We still want to move the display of this stack container to top because even the - // target position is adjusted to non-top, the intention of the condition is to have - // higher z-order to gain focus (e.g. moving a task of a fullscreen stack to front - // in a non-top display which is using picture-in-picture mode). - final int topChildPosition = getChildCount() - 1; - if (targetPosition < topChildPosition && position >= topChildPosition) { - getParent().positionChildAt(POSITION_TOP, this /* child */, - true /* includingParents */); - } + super.positionChildAt(targetPosition, child, false /* includingParents */); + + if (includingParents && (moveToTop || moveToBottom)) { + // The DisplayContent children do not re-order, but we still want to move the + // display of this stack container because the intention of positioning is to have + // higher z-order to gain focus. + positionDisplayAt(moveToTop ? POSITION_TOP : POSITION_BOTTOM, + true /* includingParents */); } setLayoutNeeded(); @@ -4688,38 +4706,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } @Override - SurfaceControl.Builder makeChildSurface(WindowContainer child) { - final SurfaceControl.Builder builder = super.makeChildSurface(child); - if (child instanceof WindowToken && ((WindowToken) child).mRoundedCornerOverlay) { - // To draw above the ColorFade layer during the screen off transition, the - // rounded corner overlays need to be at the root of the surface hierarchy. - // TODO: move the ColorLayer into the display overlay layer such that this is not - // necessary anymore. - builder.setParent(null); - } - return builder; - } - - @Override void assignChildLayers(SurfaceControl.Transaction t) { - assignChildLayers(t, null /* imeContainer */); - } - - void assignChildLayers(SurfaceControl.Transaction t, WindowContainer imeContainer) { - boolean needAssignIme = imeContainer != null - && imeContainer.getSurfaceControl() != null; + boolean needAssignIme = mImeWindowsContainers.getSurfaceControl() != null; for (int j = 0; j < mChildren.size(); ++j) { final WindowToken wt = mChildren.get(j); - // See {@link mSplitScreenDividerAnchor} - if (wt.windowType == TYPE_DOCK_DIVIDER) { - wt.assignRelativeLayer(t, mTaskStackContainers.getSplitScreenDividerAnchor(), 1); - continue; - } - if (wt.mRoundedCornerOverlay) { - wt.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1); - continue; - } wt.assignLayer(t, j); wt.assignChildLayers(t); @@ -4728,13 +4719,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (needAssignIme && layer >= mWmService.mPolicy.getWindowLayerFromTypeLw( TYPE_INPUT_METHOD_DIALOG, true)) { - imeContainer.assignRelativeLayer(t, wt.getSurfaceControl(), -1); + mImeWindowsContainers.assignRelativeLayer(t, wt.getSurfaceControl(), -1); needAssignIme = false; } } - if (needAssignIme) { - imeContainer.assignRelativeLayer(t, getSurfaceControl(), Integer.MAX_VALUE); - } } } @@ -4748,6 +4736,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo @Override void assignChildLayers(SurfaceControl.Transaction t) { + mImeWindowsContainers.setNeedsLayer(); mBelowAppWindowsContainers.assignLayer(t, 0); mTaskStackContainers.assignLayer(t, 1); mAboveAppWindowsContainers.assignLayer(t, 2); @@ -4783,15 +4772,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // TODO: We need to use an extra level on the app surface to ensure // this is always above SurfaceView but always below attached window. 1); - needAssignIme = false; } // Above we have assigned layers to our children, now we ask them to assign // layers to their children. mBelowAppWindowsContainers.assignChildLayers(t); mTaskStackContainers.assignChildLayers(t); - mAboveAppWindowsContainers.assignChildLayers(t, - needAssignIme ? mImeWindowsContainers : null); + mAboveAppWindowsContainers.assignChildLayers(t); + mImeWindowsContainers.assignRelativeLayer(t, getSurfaceControl(), Integer.MAX_VALUE); mImeWindowsContainers.assignChildLayers(t); } @@ -4807,47 +4795,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo addChild(mImeWindowsContainers, null); } - /** - * In split-screen mode we process the IME containers above the docked divider - * rather than directly above their target. - */ - private boolean skipTraverseChild(WindowContainer child) { - return child == mImeWindowsContainers && mInputMethodTarget != null - && !hasSplitScreenPrimaryStack(); - } - - @Override - boolean forAllWindows(ToBooleanFunction<WindowState> callback, - boolean traverseTopToBottom) { - // Special handling so we can process IME windows with #forAllImeWindows above their IME - // target, or here in order if there isn't an IME target. - if (traverseTopToBottom) { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final WindowContainer child = mChildren.get(i); - if (skipTraverseChild(child)) { - continue; - } - - if (child.forAllWindows(callback, traverseTopToBottom)) { - return true; - } - } - } else { - final int count = mChildren.size(); - for (int i = 0; i < count; i++) { - final WindowContainer child = mChildren.get(i); - if (skipTraverseChild(child)) { - continue; - } - - if (child.forAllWindows(callback, traverseTopToBottom)) { - return true; - } - } - } - return false; - } - @Override void positionChildAt(int position, WindowContainer child, boolean includingParents) { // Children of the WindowContainers are statically ordered, so the real intention here @@ -4961,6 +4908,68 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + /** + * Container for IME windows. + * + * This has some special behaviors: + * - layers assignment is ignored except if setNeedsLayer() has been called before (and no + * layer has been assigned since), to facilitate assigning the layer from the IME target, or + * fall back if there is no target. + * - the container doesn't always participate in window traversal, according to + * {@link #skipImeWindowsDuringTraversal()} + */ + private class ImeContainer extends NonAppWindowContainers { + boolean mNeedsLayer = false; + + ImeContainer(WindowManagerService wms) { + super("ImeContainer", wms); + } + + public void setNeedsLayer() { + mNeedsLayer = true; + } + + @Override + boolean forAllWindows(ToBooleanFunction<WindowState> callback, + boolean traverseTopToBottom) { + final DisplayContent dc = mDisplayContent; + if (skipImeWindowsDuringTraversal(dc)) { + return false; + } + return super.forAllWindows(callback, traverseTopToBottom); + } + + private boolean skipImeWindowsDuringTraversal(DisplayContent dc) { + // We skip IME windows so they're processed just above their target, except + // in split-screen mode where we process the IME containers above the docked divider. + return dc.mInputMethodTarget != null && !dc.hasSplitScreenPrimaryStack(); + } + + /** Like {@link #forAllWindows}, but ignores {@link #skipImeWindowsDuringTraversal} */ + boolean forAllWindowForce(ToBooleanFunction<WindowState> callback, + boolean traverseTopToBottom) { + return super.forAllWindows(callback, traverseTopToBottom); + } + + @Override + void assignLayer(Transaction t, int layer) { + if (!mNeedsLayer) { + return; + } + super.assignLayer(t, layer); + mNeedsLayer = false; + } + + @Override + void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { + if (!mNeedsLayer) { + return; + } + super.assignRelativeLayer(t, relativeTo, layer); + mNeedsLayer = false; + } + } + @Override SurfaceSession getSession() { return mSession; @@ -5064,6 +5073,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * with {@link WindowState#assignLayer} */ void assignRelativeLayerForImeTargetChild(SurfaceControl.Transaction t, WindowContainer child) { + mImeWindowsContainers.setNeedsLayer(); child.assignRelativeLayer(t, mImeWindowsContainers.getSurfaceControl(), 1); } @@ -5740,6 +5750,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mAtmService.mStackSupervisor.getNextTaskIdForUser(); } + ActivityStack createStack(int windowingMode, int activityType, boolean onTop) { + return createStack(windowingMode, activityType, onTop, null /*info*/, null /*intent*/); + } + /** * Creates a stack matching the input windowing mode and activity type on this display. * @param windowingMode The windowing mode the stack should be created in. If @@ -5751,13 +5765,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * @param onTop If true the stack will be created at the top of the display, else at the bottom. * @return The newly created stack. */ - ActivityStack createStack(int windowingMode, int activityType, boolean onTop) { + ActivityStack createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info, + Intent intent) { if (mSingleTaskInstance && getStackCount() > 0) { // Create stack on default display instead since this display can only contain 1 stack. // TODO: Kinda a hack, but better that having the decision at each call point. Hoping // this goes away once ActivityView is no longer using virtual displays. return mRootWindowContainer.getDefaultDisplay().createStack( - windowingMode, activityType, onTop); + windowingMode, activityType, onTop, info, intent); } if (activityType == ACTIVITY_TYPE_UNDEFINED) { @@ -5785,18 +5800,23 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } final int stackId = getNextStackId(); - return createStackUnchecked(windowingMode, activityType, stackId, onTop); + return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent); } @VisibleForTesting ActivityStack createStackUnchecked(int windowingMode, int activityType, - int stackId, boolean onTop) { + int stackId, boolean onTop, ActivityInfo info, Intent intent) { if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) { throw new IllegalArgumentException("Stack with windowing mode cannot with non standard " + "activity type."); } + if (info == null) { + info = new ActivityInfo(); + info.applicationInfo = new ApplicationInfo(); + } + final ActivityStack stack = new ActivityStack(this, stackId, - mRootWindowContainer.mStackSupervisor, activityType); + mRootWindowContainer.mStackSupervisor, activityType, info, intent); addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM); stack.setWindowingMode(windowingMode, false /* animate */, false /* showRecents */, false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */, diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 5df80fcc7c06..e1dfc177a881 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -32,7 +32,6 @@ import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.Process.SYSTEM_UID; -import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; @@ -1382,7 +1381,7 @@ class RecentTasks { // Ignore tasks from different displays // TODO (b/115289124): No Recents on non-default displays. - if (stack.getDisplayId() != DEFAULT_DISPLAY) { + if (!stack.isOnHomeDisplay()) { return false; } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index b255b5eb7c0e..614809505dee 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -374,7 +374,7 @@ public class RecentsAnimationController implements DeathRecipient { final PooledConsumer c = PooledLambda.obtainConsumer((t, outList) -> { if (!outList.contains(t)) outList.add(t); }, PooledLambda.__(Task.class), visibleTasks); - targetStack.forAllTasks(c); + targetStack.forAllTasks(c, true /* traverseTopToBottom */, targetStack); c.recycle(); } diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java index e310fc18b6a7..2f61ca05ada5 100644 --- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java +++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java @@ -247,8 +247,7 @@ class ResetTargetTaskHelper { } else { targetTask = mTargetStack.createTask( atmService.mStackSupervisor.getNextTaskIdForUser(r.mUserId), r.info, - null /* intent */, null /* voiceSession */, null /* voiceInteractor */, - false /* toTop */); + null /* intent */, false /* toTop */); targetTask.affinityIntent = r.intent; createdTasks.add(targetTask); if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 8b1005e2e847..8202833783a9 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2131,23 +2131,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // We will then perform a windowing mode change for both scenarios. stack = display.createStack( r.getActivityStack().getRequestedOverrideWindowingMode(), - r.getActivityType(), ON_TOP); + r.getActivityType(), ON_TOP, r.info, r.intent); // There are multiple activities in the task and moving the top activity should // reveal/leave the other activities in their original task. - // Currently, we don't support reparenting activities across tasks in two different - // stacks, so instead, just create a new task in the same stack, reparent the - // activity into that task, and then reparent the whole task to the new stack. This - // ensures that all the necessary work to migrate states in the old and new stacks - // is also done. - final Task newTask = task.getStack().createTask( - mStackSupervisor.getNextTaskIdForUser(r.mUserId), r.info, - r.intent, null, null, true); + Task newTask = stack.createTask(mStackSupervisor.getNextTaskIdForUser(r.mUserId), + r.info, r.intent, true); r.reparent(newTask, MAX_VALUE, "moveActivityToStack"); - - // Defer resume until below, and do not schedule PiP changes until we animate below - newTask.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, - DEFER_RESUME, false /* schedulePictureInPictureModeChange */, reason); } stack.setWindowingMode(WINDOWING_MODE_PINNED); @@ -2416,17 +2406,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent> info.position = display != null ? display.getIndexOf(stack) : 0; info.configuration.setTo(stack.getConfiguration()); - final int numTasks = stack.getChildCount(); + final int numTasks = stack.getDescendantTaskCount(); info.taskIds = new int[numTasks]; info.taskNames = new String[numTasks]; info.taskBounds = new Rect[numTasks]; info.taskUserIds = new int[numTasks]; - final int[] currenIndex = {0}; + final int[] currentIndex = {0}; final PooledConsumer c = PooledLambda.obtainConsumer( RootWindowContainer::processTaskForStackInfo, PooledLambda.__(Task.class), info, - currenIndex); - stack.forAllTasks(c, false); + currentIndex); + stack.forAllTasks(c, false /* traverseTopToBottom */, stack); c.recycle(); final ActivityRecord top = stack.topRunningActivity(); @@ -2569,7 +2559,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } ActivityStack findStackBehind(ActivityStack stack) { - final DisplayContent display = getDisplayContent(stack.getDisplayId()); + final DisplayContent display = stack.getDisplayContent(); if (display != null) { for (int i = display.getStackCount() - 1; i >= 0; i--) { if (display.getStackAt(i) == stack && i > 0) { diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java index 98127ab2eec8..6ebbf776feba 100644 --- a/services/core/java/com/android/server/wm/RunningTasks.java +++ b/services/core/java/com/android/server/wm/RunningTasks.java @@ -93,6 +93,9 @@ class RunningTasks { } private void processTask(Task task) { + if (task.isRootTask()) { + return; + } if (task.getTopNonFinishingActivity() == null) { // Skip if there are no activities in the task return; diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 3b349b817108..5babdafc856d 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -31,6 +31,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.Nullable; import android.content.ClipData; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.os.Binder; @@ -189,7 +190,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { Rect outFrame, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, - SurfaceControl outSurfaceControl, InsetsState outInsetsState) { + SurfaceControl outSurfaceControl, InsetsState outInsetsState, + Point outSurfaceSize) { if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag); @@ -197,7 +199,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { requestedWidth, requestedHeight, viewFlags, flags, frameNumber, outFrame, outContentInsets, outVisibleInsets, outStableInsets, outBackdropFrame, cutout, - mergedConfiguration, outSurfaceControl, outInsetsState); + mergedConfiguration, outSurfaceControl, outInsetsState, outSurfaceSize); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index b7201b4dbde5..9e6cb6884820 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -30,6 +30,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.app.WindowConfiguration.activityTypeToString; +import static android.app.WindowConfiguration.windowingModeToString; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; @@ -69,6 +71,7 @@ import static com.android.server.am.TaskRecordProto.RESIZE_MODE; import static com.android.server.am.TaskRecordProto.STACK_ID; import static com.android.server.am.TaskRecordProto.TASK; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; +import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; @@ -82,6 +85,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECEN import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS; @@ -93,6 +97,7 @@ import static com.android.server.wm.TaskProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; @@ -202,9 +207,9 @@ class Task extends WindowContainer<WindowContainer> { // Current version of the task record we persist. Used to check if we need to run any upgrade // code. - private static final int PERSIST_TASK_VERSION = 1; + static final int PERSIST_TASK_VERSION = 1; - private static final int INVALID_MIN_SIZE = -1; + static final int INVALID_MIN_SIZE = -1; /** * The modes to control how the stack is moved to the front when calling {@link Task#reparent}. @@ -331,6 +336,8 @@ class Task extends WindowContainer<WindowContainer> { final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport(); final ActivityTaskManagerService mAtmService; + final ActivityStackSupervisor mStackSupervisor; + final RootWindowContainer mRootWindowContainer; /* Unique identifier for this task. */ final int mTaskId; @@ -345,8 +352,12 @@ class Task extends WindowContainer<WindowContainer> { // TODO(b/119687367): This member is temporary. private final Rect mOverrideDisplayedBounds = new Rect(); + // Id of the previous display the stack was on. + int mPrevDisplayId = INVALID_DISPLAY; + /** ID of the display which rotation {@link #mRotation} has. */ private int mLastRotationDisplayId = INVALID_DISPLAY; + /** * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was * moved to a new display. @@ -388,8 +399,37 @@ class Task extends WindowContainer<WindowContainer> { private static Exception sTmpException; + /** ActivityRecords that are exiting, but still on screen for animations. */ + final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>(); + + /** + * When we are in the process of pausing an activity, before starting the + * next one, this variable holds the activity that is currently being paused. + */ + ActivityRecord mPausingActivity = null; + + /** + * This is the last activity that we put into the paused state. This is + * used to determine if we need to do an activity transition while sleeping, + * when we normally hold the top activity paused. + */ + ActivityRecord mLastPausedActivity = null; + + /** + * Activities that specify No History must be removed once the user navigates away from them. + * If the device goes to sleep with such an activity in the paused state then we save it here + * and finish it later if another activity replaces it on wakeup. + */ + ActivityRecord mLastNoHistoryActivity = null; + + /** Current activity that is resumed, or null if there is none. */ + ActivityRecord mResumedActivity = null; + private boolean mForceShowForAllUsers; + /** When set, will force the task to report as invisible. */ + boolean mForceHidden = false; + private final FindRootHelper mFindRootHelper = new FindRootHelper(); private class FindRootHelper { private ActivityRecord mRoot; @@ -488,6 +528,8 @@ class Task extends WindowContainer<WindowContainer> { EventLogTags.writeWmTaskCreated(_taskId, stack != null ? stack.mStackId : INVALID_STACK_ID); mAtmService = atmService; + mStackSupervisor = atmService.mStackSupervisor; + mRootWindowContainer = mAtmService.mRootWindowContainer; mTaskId = _taskId; mUserId = _userId; mResizeMode = resizeMode; @@ -551,7 +593,7 @@ class Task extends WindowContainer<WindowContainer> { if (autoRemoveFromRecents() || isVoiceSession) { // Task creator asked to remove this when done, or this task was a voice // interaction, so it should not remain on the recent tasks list. - mAtmService.mStackSupervisor.mRecentTasks.remove(this); + mStackSupervisor.mRecentTasks.remove(this); } removeIfPossible(); @@ -560,13 +602,18 @@ class Task extends WindowContainer<WindowContainer> { @VisibleForTesting @Override void removeIfPossible() { - mAtmService.getLockTaskController().clearLockedTask(this); + final boolean isRootTask = isRootTask(); + if (!isRootTask) { + mAtmService.getLockTaskController().clearLockedTask(this); + } if (shouldDeferRemoval()) { if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId); return; } removeImmediately(); - mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId); + if (!isRootTask) { + mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId); + } } void setResizeMode(int resizeMode) { @@ -574,8 +621,8 @@ class Task extends WindowContainer<WindowContainer> { return; } mResizeMode = resizeMode; - mAtmService.mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); - mAtmService.mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); + mRootWindowContainer.resumeFocusedStacksTopActivities(); updateTaskDescription(); } @@ -592,7 +639,7 @@ class Task extends WindowContainer<WindowContainer> { setBounds(bounds); if (!inFreeformWindowingMode()) { // re-restore the task so it can have the proper stack association. - mAtmService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP); + mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP); } return true; } @@ -628,10 +675,9 @@ class Task extends WindowContainer<WindowContainer> { // this won't cause tons of irrelevant windows being preserved because only // activities in this task may experience a bounds change. Configs for other // activities stay the same. - mAtmService.mRootWindowContainer.ensureActivitiesVisible(r, 0, - preserveWindow); + mRootWindowContainer.ensureActivitiesVisible(r, 0, preserveWindow); if (!kept) { - mAtmService.mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedStacksTopActivities(); } } } @@ -695,8 +741,8 @@ class Task extends WindowContainer<WindowContainer> { boolean reparent(ActivityStack preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason) { - final ActivityStackSupervisor supervisor = mAtmService.mStackSupervisor; - final RootWindowContainer root = mAtmService.mRootWindowContainer; + final ActivityStackSupervisor supervisor = mStackSupervisor; + final RootWindowContainer root = mRootWindowContainer; final WindowManagerService windowManager = mAtmService.mWindowManager; final ActivityStack sourceStack = getStack(); final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack, @@ -765,7 +811,7 @@ class Task extends WindowContainer<WindowContainer> { wasPaused, reason); } if (!animate) { - mAtmService.mStackSupervisor.mNoAnimActivities.add(topActivity); + mStackSupervisor.mNoAnimActivities.add(topActivity); } // We might trigger a configuration change. Save the current task bounds for freezing. @@ -784,7 +830,7 @@ class Task extends WindowContainer<WindowContainer> { } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) { Rect bounds = getLaunchBounds(); if (bounds == null) { - mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null); + mStackSupervisor.getLaunchParamsController().layoutTask(this, null); bounds = configBounds; } kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume); @@ -792,7 +838,7 @@ class Task extends WindowContainer<WindowContainer> { if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) { // Move recents to front so it is not behind home stack when going into docked // mode - mAtmService.mStackSupervisor.moveRecentsStackToFront(reason); + mStackSupervisor.moveRecentsStackToFront(reason); } kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM, !mightReplaceWindow, deferResume); @@ -858,6 +904,14 @@ class Task extends WindowContainer<WindowContainer> { mCallingPackage = r.launchedFromPackage; setIntent(r.intent, r.info); setLockTaskAuth(r); + + final WindowContainer parent = getParent(); + if (parent != null) { + final Task t = parent.asTask(); + if (t != null) { + t.setIntent(r); + } + } } /** Sets the original intent, _without_ updating the calling uid or package. */ @@ -971,8 +1025,13 @@ class Task extends WindowContainer<WindowContainer> { } boolean returnsToHomeStack() { - final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME; - return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags; + if (inMultiWindowMode() || !hasChild()) return false; + if (intent != null) { + final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME; + return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags; + } + final Task bottomTask = getBottomMostTask(); + return bottomTask != this && bottomTask.returnsToHomeStack(); } void setPrevAffiliate(Task prevAffiliate) { @@ -987,37 +1046,72 @@ class Task extends WindowContainer<WindowContainer> { @Override void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { - final ActivityStack oldStack = ((ActivityStack) oldParent); - final ActivityStack newStack = ((ActivityStack) newParent); + final DisplayContent display = newParent != null + ? ((WindowContainer) newParent).getDisplayContent() : null; + final DisplayContent oldDisplay = oldParent != null + ? ((WindowContainer) oldParent).getDisplayContent() : null; + + mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY; // Task is going to be removed, clean it up before detaching from hierarchy. if (oldParent != null && newParent == null) { cleanUpResourcesForDestroy(); } + if (display != null) { + // TODO(NOW!): Chat with the erosky@ of this code to see if this really makes sense here... + // Rotations are relative to the display. This means if there are 2 displays rotated + // differently (eg. 2 monitors with one landscape and one portrait), moving a stack + // from one to the other could look like a rotation change. To prevent this + // apparent rotation change (and corresponding bounds rotation), pretend like our + // current rotation is already the same as the new display. + // Note, if ActivityStack or related logic ever gets nested, this logic will need + // to move to onConfigurationChanged. + getConfiguration().windowConfiguration.setRotation( + display.getWindowConfiguration().getRotation()); + } + super.onParentChanged(newParent, oldParent); - if (oldStack != null) { - final PooledConsumer c = PooledLambda.obtainConsumer( - ActivityStack::onActivityRemovedFromStack, oldStack, - PooledLambda.__(ActivityRecord.class)); - forAllActivities(c); - c.recycle(); + // TODO(NOW): The check for null display content and setting it to null doesn't really + // make sense here... + + // TODO(stack-merge): This is mostly taking care of the case where the stask is removing from + // the display, so we should probably consolidate it there instead. + + if (getParent() == null && mDisplayContent != null) { + EventLogTags.writeWmStackRemoved(getStackId()); + mDisplayContent = null; + mWmService.mWindowPlacerLocked.requestTraversal(); + } - if (oldStack.inPinnedWindowingMode() - && (newStack == null || !newStack.inPinnedWindowingMode())) { + if (oldParent != null) { + final Task oldParentTask = ((WindowContainer) oldParent).asTask(); + if (oldParentTask != null) { + final PooledConsumer c = PooledLambda.obtainConsumer( + Task::cleanUpActivityReferences, oldParentTask, + PooledLambda.__(ActivityRecord.class)); + forAllActivities(c); + c.recycle(); + } + + if (oldParent.inPinnedWindowingMode() + && (newParent == null || !newParent.inPinnedWindowingMode())) { // Notify if a task from the pinned stack is being removed // (or moved depending on the mode). mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned(); } } - if (newStack != null) { - final PooledConsumer c = PooledLambda.obtainConsumer( - ActivityStack::onActivityAddedToStack, newStack, - PooledLambda.__(ActivityRecord.class)); - forAllActivities(c); - c.recycle(); + if (newParent != null) { + final Task newParentTask = ((WindowContainer) newParent).asTask(); + if (newParentTask != null) { + final ActivityRecord top = newParentTask.getTopNonFinishingActivity( + false /* includeOverlays */); + if (top != null && top.isState(RESUMED)) { + newParentTask.setResumedActivity(top, "addedToTask"); + } + } // TODO: Ensure that this is actually necessary here // Notify the voice session if required @@ -1048,7 +1142,41 @@ class Task extends WindowContainer<WindowContainer> { forceWindowsScaleable(false /* force */); } - mAtmService.mRootWindowContainer.updateUIDsPresentOnDisplay(); + mRootWindowContainer.updateUIDsPresentOnDisplay(); + } + + void cleanUpActivityReferences(ActivityRecord r) { + final WindowContainer parent = getParent(); + if (parent != null && parent.asTask() != null) { + parent.asTask().cleanUpActivityReferences(r); + return; + } + r.removeTimeouts(); + mExitingActivities.remove(r); + + if (mResumedActivity != null && mResumedActivity == r) { + setResumedActivity(null, "cleanUpActivityReferences"); + } + if (mPausingActivity != null && mPausingActivity == r) { + mPausingActivity = null; + } + } + + /** @return the currently resumed activity. */ + ActivityRecord getResumedActivity() { + return mResumedActivity; + } + + void setResumedActivity(ActivityRecord r, String reason) { + if (mResumedActivity == r) { + return; + } + + if (ActivityTaskManagerDebugConfig.DEBUG_STACK) Slog.d(TAG_STACK, + "setResumedActivity stack:" + this + " + from: " + + mResumedActivity + " to:" + r + " reason:" + reason); + mResumedActivity = r; + mStackSupervisor.updateTopResumedActivityIfNeeded(); } void updateTaskMovement(boolean toFront) { @@ -1061,7 +1189,7 @@ class Task extends WindowContainer<WindowContainer> { mLastTimeMoved *= -1; } } - mAtmService.mRootWindowContainer.invalidateTaskLayers(); + mRootWindowContainer.invalidateTaskLayers(); } // Close up recents linked list. @@ -1114,7 +1242,11 @@ class Task extends WindowContainer<WindowContainer> { /** Returns the intent for the root activity for this task */ Intent getBaseIntent() { - return intent != null ? intent : affinityIntent; + if (intent != null) return intent; + if (affinityIntent != null) return affinityIntent; + // Probably a task that contains other tasks, so return the intent for the top task? + final Task topTask = getTopMostTask(); + return topTask != null ? topTask.getBaseIntent() : null; } /** Returns the first non-finishing activity from the bottom. */ @@ -1199,11 +1331,18 @@ class Task extends WindowContainer<WindowContainer> { // If this task had any child before we added this one. boolean hadChild = hasChild(); - final ActivityRecord r = (ActivityRecord) child; - index = getAdjustedAddPosition(r, index); - super.addChild(r, index); + index = getAdjustedChildPosition(child, index); + super.addChild(child, index); ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this); + + // Make sure the list of display UID whitelists is updated + // now that this record is in a new task. + mRootWindowContainer.updateUIDsPresentOnDisplay(); + + final ActivityRecord r = child.asActivityRecord(); + if (r == null) return; + r.inHistory = true; // Only set this based on the first activity @@ -1228,10 +1367,6 @@ class Task extends WindowContainer<WindowContainer> { } updateEffectiveIntent(); - - // Make sure the list of display UID whitelists is updated - // now that this record is in a new task. - mAtmService.mRootWindowContainer.updateUIDsPresentOnDisplay(); } void addChild(ActivityRecord r) { @@ -1239,12 +1374,19 @@ class Task extends WindowContainer<WindowContainer> { } @Override - void removeChild(WindowContainer r) { + void removeChild(WindowContainer child) { + removeChild(child, "removeChild"); + } + + void removeChild(WindowContainer r, String reason) { if (!mChildren.contains(r)) { Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this); return; } + if (DEBUG_TASK_MOVEMENT) { + Slog.d(TAG_WM, "removeChild: child=" + r + " reason=" + reason); + } super.removeChild(r); if (inPinnedWindowingMode()) { @@ -1254,7 +1396,15 @@ class Task extends WindowContainer<WindowContainer> { mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged(); } - final String reason = "removeChild"; + final boolean isRootTask = isRootTask(); + if (isRootTask) { + final DisplayContent display = getDisplayContent(); + if (display.isSingleTaskInstance()) { + mAtmService.notifySingleTaskDisplayEmpty(display.mDisplayId); + } + display.mDisplayContent.setLayoutNeeded(); + } + if (hasChild()) { updateEffectiveIntent(); @@ -1269,12 +1419,14 @@ class Task extends WindowContainer<WindowContainer> { // work. // TODO: If the callers to removeChild() changes such that we have multiple places // where we are destroying the task, move this back into removeChild() - mAtmService.mStackSupervisor.removeTask(this, false /* killProcess */, + mStackSupervisor.removeTask(this, false /* killProcess */, !REMOVE_FROM_RECENTS, reason); } } else if (!mReuseTask) { // Remove entire task if it doesn't have any activity left and it isn't marked for reuse - getStack().removeChild(this, reason); + if (!isRootTask) { + getStack().removeChild(this, reason); + } EventLogTags.writeWmTaskRemoved(mTaskId, "removeChild: last r=" + r + " in t=" + this); removeIfPossible(); @@ -1445,11 +1597,15 @@ class Task extends WindowContainer<WindowContainer> { @Override public boolean supportsSplitScreenWindowingMode() { + final Task topTask = getTopMostTask(); + return super.supportsSplitScreenWindowingMode() + && (topTask == null || topTask.supportsSplitScreenWindowingModeInner()); + } + + private boolean supportsSplitScreenWindowingModeInner() { // A task can not be docked even if it is considered resizeable because it only supports // picture-in-picture mode but has a non-resizeable resizeMode return super.supportsSplitScreenWindowingMode() - // TODO(task-group): Probably makes sense to move this and associated code into - // WindowContainer so it affects every node. && mAtmService.mSupportsSplitScreenMultiWindow && (mAtmService.mForceResizableActivities || (isResizeable(false /* checkSupportsPip */) @@ -1464,7 +1620,7 @@ class Task extends WindowContainer<WindowContainer> { * secondary display. */ boolean canBeLaunchedOnDisplay(int displayId) { - return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId, + return mStackSupervisor.canPlaceEntityOnDisplay(displayId, -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */); } @@ -1534,6 +1690,14 @@ class Task extends WindowContainer<WindowContainer> { } mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged( getTaskInfo()); + + final WindowContainer parent = getParent(); + if (parent != null) { + final Task t = parent.asTask(); + if (t != null) { + t.updateTaskDescription(); + } + } } private static boolean setTaskDescriptionFromActivityAboveRoot( @@ -1576,9 +1740,11 @@ class Task extends WindowContainer<WindowContainer> { @VisibleForTesting void updateEffectiveIntent() { final ActivityRecord root = getRootActivity(true /*setToBottomIfNone*/); - setIntent(root); - // Update the task description when the activities change - updateTaskDescription(); + if (root != null) { + setIntent(root); + // Update the task description when the activities change + updateTaskDescription(); + } } void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) { @@ -1592,9 +1758,8 @@ class Task extends WindowContainer<WindowContainer> { // If the task has no requested minimal size, we'd like to enforce a minimal size // so that the user can not render the task too small to manipulate. We don't need // to do this for the pinned stack as the bounds are controlled by the system. - if (!inPinnedWindowingMode() && getDisplayContent() != null) { - final int defaultMinSizeDp = - mAtmService.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp; + if (!inPinnedWindowingMode() && getStack() != null) { + final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp; final DisplayContent display = getDisplayContent(); final float density = (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT; @@ -1658,10 +1823,25 @@ class Task extends WindowContainer<WindowContainer> { * @param reason The reason for the change. */ void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) { - final ActivityStack parent = getStack(); + final Task parentTask = getParent().asTask(); + if (parentTask != null) { + parentTask.onActivityStateChanged(record, state, reason); + return; + } - if (parent != null) { - parent.onActivityStateChanged(record, state, reason); + if (record == mResumedActivity && state != RESUMED) { + setResumedActivity(null, reason + " - onActivityStateChanged"); + } + + if (state == RESUMED) { + if (ActivityTaskManagerDebugConfig.DEBUG_STACK) { + Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:" + reason); + } + setResumedActivity(record, reason + " - onActivityStateChanged"); + if (record == mRootWindowContainer.getTopResumedActivity()) { + mAtmService.setResumedActivityUncheckLocked(record, reason); + } + mStackSupervisor.mRecentTasks.add(record.getTask()); } } @@ -1683,7 +1863,7 @@ class Task extends WindowContainer<WindowContainer> { final boolean wasInMultiWindowMode = inMultiWindowMode(); super.onConfigurationChanged(newParentConfig); if (wasInMultiWindowMode != inMultiWindowMode()) { - mAtmService.mStackSupervisor.scheduleUpdateMultiWindowMode(this); + mStackSupervisor.scheduleUpdateMultiWindowMode(this); } // If the configuration supports persistent bounds (eg. Freeform), keep track of the @@ -1724,7 +1904,7 @@ class Task extends WindowContainer<WindowContainer> { } // Saves the new state so that we can launch the activity at the same location. - mAtmService.mStackSupervisor.mLaunchParamsPersister.saveTask(this); + mStackSupervisor.mLaunchParamsPersister.saveTask(this); } /** @@ -1986,6 +2166,10 @@ class Task extends WindowContainer<WindowContainer> { @Override void resolveOverrideConfiguration(Configuration newParentConfig) { + if (isRootTask()) { + super.resolveOverrideConfiguration(newParentConfig); + return; + } mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds()); super.resolveOverrideConfiguration(newParentConfig); int windowingMode = @@ -2010,12 +2194,12 @@ class Task extends WindowContainer<WindowContainer> { final Rect parentBounds = new Rect(newParentConfig.windowConfiguration.getBounds()); final DisplayContent display = getDisplayContent(); - if (display != null && display.mDisplayContent != null) { + if (display != null) { // If a freeform window moves below system bar, there is no way to move it again // by touch. Because its caption is covered by system bar. So we exclude them // from stack bounds. and then caption will be shown inside stable area. final Rect stableBounds = new Rect(); - display.mDisplayContent.getStableRect(stableBounds); + display.getStableRect(stableBounds); parentBounds.intersect(stableBounds); } @@ -2090,6 +2274,7 @@ class Task extends WindowContainer<WindowContainer> { * input stack. */ void updateOverrideConfigurationForStack(ActivityStack inStack) { final ActivityStack stack = getStack(); + if (stack != null && stack == inStack) { return; } @@ -2105,7 +2290,7 @@ class Task extends WindowContainer<WindowContainer> { if (mLastNonFullscreenBounds != null) { setBounds(mLastNonFullscreenBounds); } else { - mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null); + mStackSupervisor.getLaunchParamsController().layoutTask(this, null); } } else { setBounds(inStack.getRequestedOverrideBounds()); @@ -2148,7 +2333,10 @@ class Task extends WindowContainer<WindowContainer> { @Override DisplayContent getDisplayContent() { - return getStack() != null ? getStack().getDisplayContent() : null; + // TODO: Why aren't we just using our own display content vs. parent's??? + final ActivityStack stack = getStack(); + return stack != null && stack != this + ? stack.getDisplayContent() : super.getDisplayContent(); } int getDisplayId() { @@ -2157,7 +2345,8 @@ class Task extends WindowContainer<WindowContainer> { } ActivityStack getStack() { - return (ActivityStack) getParent(); + final WindowContainer parent = getParent(); + return (ActivityStack) (parent instanceof ActivityStack ? parent : this); } /** @@ -2168,27 +2357,99 @@ class Task extends WindowContainer<WindowContainer> { return stack != null ? stack.mStackId : INVALID_STACK_ID; } - // TODO(task-hierarchy): Needs to take a generic WindowManager when task contains other tasks. - int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) { - int maxPosition = mChildren.size(); - if (!r.isTaskOverlay()) { - // We want to place all non-overlay activities below overlays. - final ActivityRecord bottomMostOverlay = getActivity((ar) -> ar.isTaskOverlay(), false); - if (bottomMostOverlay != null) { - maxPosition = Math.max(mChildren.indexOf(bottomMostOverlay) - 1, 0); + int getDescendantTaskCount() { + final int[] currentCount = {0}; + final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; }, + PooledLambda.__(Task.class), currentCount); + forAllTasks(c, false /* traverseTopToBottom */, this); + c.recycle(); + return currentCount[0]; + } + + /** Calculate the minimum possible position for a task that can be shown to the user. + * The minimum position will be above all other tasks that can't be shown. + * @param minPosition The minimum position the caller is suggesting. + * We will start adjusting up from here. + * @param size The size of the current task list. + */ + // TODO: Move user to their own window container. + private int computeMinUserPosition(int minPosition, int size) { + while (minPosition < size) { + final WindowContainer child = mChildren.get(minPosition); + final boolean canShow = child.showToCurrentUser(); + if (canShow) { + break; + } + minPosition++; + } + return minPosition; + } + + /** Calculate the maximum possible position for a task that can't be shown to the user. + * The maximum position will be below all other tasks that can be shown. + * @param maxPosition The maximum position the caller is suggesting. + * We will start adjusting down from here. + */ + // TODO: Move user to their own window container. + private int computeMaxUserPosition(int maxPosition) { + while (maxPosition > 0) { + final WindowContainer child = mChildren.get(maxPosition); + final boolean canShow = child.showToCurrentUser(); + if (!canShow) { + break; + } + maxPosition--; + } + return maxPosition; + } + + private int getAdjustedChildPosition(WindowContainer wc, int suggestedPosition) { + final boolean canShowChild = wc.showToCurrentUser(); + + final int size = mChildren.size(); + + // Figure-out min/max possible position depending on if child can show for current user. + int minPosition = (canShowChild) ? computeMinUserPosition(0, size) : 0; + int maxPosition = (canShowChild) ? size : computeMaxUserPosition(size - 1); + + // Factor in always-on-top children in max possible position. + if (!wc.isAlwaysOnTop()) { + + // We want to place all non-always-on-top containers below always-on-top ones. + while (maxPosition > minPosition) { + if (!mChildren.get(maxPosition - 1).isAlwaysOnTop()) break; + --maxPosition; } } - return Math.min(maxPosition, suggestedPosition); + // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid. + if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) { + return POSITION_BOTTOM; + } else if (suggestedPosition == POSITION_TOP && maxPosition == (size - 1)) { + return POSITION_TOP; + } + // Reset position based on minimum/maximum possible positions. + return Math.min(Math.max(suggestedPosition, minPosition), maxPosition); } @Override void positionChildAt(int position, WindowContainer child, boolean includingParents) { - position = getAdjustedAddPosition((ActivityRecord) child, position); + position = getAdjustedChildPosition(child, position); super.positionChildAt(position, child, includingParents); + + // Log positioning. + if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "positionChildAt: child=" + child + + " position=" + position + " parent=" + this); + + final int toTop = position >= (mChildren.size() - 1) ? 1 : 0; + final Task task = child.asTask(); + if (task != null) { + EventLogTags.writeWmTaskMoved(task.mTaskId, toTop, position); + } } - private boolean hasWindowsAlive() { + @VisibleForTesting + boolean hasWindowsAlive() { return getActivity(ActivityRecord::hasWindowsAlive) != null; } @@ -2218,8 +2479,6 @@ class Task extends WindowContainer<WindowContainer> { + " from stack=" + getStack()); EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason); - position = stack.findPositionForTask(this, position); - reparent(stack, position); stack.positionChildAt(position, this, moveParents); @@ -2285,11 +2544,16 @@ class Task extends WindowContainer<WindowContainer> { @Override void onDisplayChanged(DisplayContent dc) { - adjustBoundsForDisplayChangeIfNeeded(dc); + final boolean isRootTask = isRootTask(); + if (!isRootTask) { + adjustBoundsForDisplayChangeIfNeeded(dc); + } super.onDisplayChanged(dc); - final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY; - mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged( - mTaskId, displayId); + if (!isRootTask) { + final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY; + mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged( + mTaskId, displayId); + } } /** @@ -2431,7 +2695,7 @@ class Task extends WindowContainer<WindowContainer> { } /** Bounds of the task to be used for dimming, as well as touch related tests. */ - public void getDimBounds(Rect out) { + void getDimBounds(Rect out) { final DisplayContent displayContent = getStack().getDisplayContent(); // It doesn't matter if we in particular are part of the resize, since we couldn't have // a DimLayer anyway if we weren't visible. @@ -2564,6 +2828,11 @@ class Task extends WindowContainer<WindowContainer> { mForceShowForAllUsers = forceShowForAllUsers; } + public boolean isAttached() { + final DisplayContent display = getDisplayContent(); + return display != null && !display.isRemoved(); + } + /** * When we are in a floating stack (Freeform, Pinned, ...) we calculate * insets differently. However if we are animating to the fullscreen stack @@ -2575,6 +2844,45 @@ class Task extends WindowContainer<WindowContainer> { && !getStack().isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState; } + /** + * Returns true if the stack is translucent and can have other contents visible behind it if + * needed. A stack is considered translucent if it don't contain a visible or + * starting (about to be visible) activity that is fullscreen (opaque). + * @param starting The currently starting activity or null if there is none. + */ + @VisibleForTesting + boolean isTranslucent(ActivityRecord starting) { + if (!isAttached() || mForceHidden) { + return true; + } + final PooledPredicate p = PooledLambda.obtainPredicate(Task::isOpaqueActivity, + PooledLambda.__(ActivityRecord.class), starting); + final ActivityRecord opaque = getActivity(p); + p.recycle(); + return opaque == null; + } + + private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) { + if (r.finishing) { + // We don't factor in finishing activities when determining translucency since + // they will be gone soon. + return false; + } + + if (!r.visibleIgnoringKeyguard && r != starting) { + // Also ignore invisible activities that are not the currently starting + // activity (about to be visible). + return false; + } + + if (r.occludesParent() || r.hasWallpaper) { + // Stack isn't translucent if it has at least one fullscreen activity + // that is visible. + return true; + } + return false; + } + @Override public SurfaceControl getAnimationLeashParent() { if (WindowManagerService.sHierarchicalAnimations) { @@ -2626,7 +2934,7 @@ class Task extends WindowContainer<WindowContainer> { return true; } } - return false; + return forAllTasks((t) -> { return t != this && t.isTaskAnimating(); }); } /** @@ -2702,26 +3010,45 @@ class Task extends WindowContainer<WindowContainer> { return mTaskDescription; } + // TODO(task-merge): Figure out what's the right thing to do for places that used it. + boolean isRootTask() { + return getParent() == null || getParent().asTask() == null; + } + @Override boolean fillsParent() { - return matchParentBounds() || !getWindowConfiguration().canResizeTask(); + return matchParentBounds(); + } + + void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom, Task excludedTask) { + if (traverseTopToBottom) { + super.forAllTasks(callback, traverseTopToBottom); + if (excludedTask != this) { + callback.accept(this); + } + } else { + super.forAllTasks(callback, traverseTopToBottom); + if (excludedTask != this) { + callback.accept(this); + } + } } @Override void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) { - // TODO(task-hierarchy): Change to traverse children when tasks can contain other tasks. - callback.accept(this); + forAllTasks(callback, traverseTopToBottom, null /* excludedTask */); } @Override boolean forAllTasks(Function<Task, Boolean> callback) { + if (super.forAllTasks(callback)) return true; return callback.apply(this); } @Override Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) { - // I'm a task! - // TODO(task-hierarchy): Change to traverse children when tasks can contain other tasks. + final Task t = super.getTask(callback, traverseTopToBottom); + if (t != null) return t; return callback.test(this) ? this : null; } @@ -2757,6 +3084,16 @@ class Task extends WindowContainer<WindowContainer> { return mDimmer; } + void dim(float alpha) { + mDimmer.dimAbove(getPendingTransaction(), alpha); + scheduleAnimation(); + } + + void stopDimming() { + mDimmer.stopDim(getPendingTransaction()); + scheduleAnimation(); + } + boolean isTaskForUser(int userId) { return mUserId == userId; } @@ -2804,7 +3141,7 @@ class Task extends WindowContainer<WindowContainer> { } @Override - public void dump(PrintWriter pw, String prefix, boolean dumpAll) { + void dump(PrintWriter pw, String prefix, boolean dumpAll) { super.dump(pw, prefix, dumpAll); final String doublePrefix = prefix + " "; @@ -2864,6 +3201,17 @@ class Task extends WindowContainer<WindowContainer> { return mTaskId == taskId; } + @Override + Task asTask() { + // I'm a task! + return this; + } + + // TODO(task-merge): Figure-out how this should work with hierarchy tasks. + boolean shouldBeVisible(ActivityRecord starting) { + return true; + } + void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("userId="); pw.print(mUserId); pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); @@ -2950,7 +3298,7 @@ class Task extends WindowContainer<WindowContainer> { if (mRootProcess != null) { pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess); } - pw.print(prefix); pw.print("stackId="); pw.println(getStackId()); + pw.print(prefix); pw.print("taskId=" + mTaskId); pw.println(" stackId=" + getStackId()); pw.print(prefix + "hasBeenVisible=" + hasBeenVisible); pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode)); pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture); @@ -2977,6 +3325,10 @@ class Task extends WindowContainer<WindowContainer> { sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(" #"); sb.append(mTaskId); + sb.append(" visible=" + shouldBeVisible(null /* starting */)); + sb.append(" type=" + activityTypeToString(getActivityType())); + sb.append(" mode=" + windowingModeToString(getWindowingMode())); + sb.append(" translucent=" + isTranslucent(null /* starting */)); if (affinity != null) { sb.append(" A="); sb.append(affinity); @@ -2993,8 +3345,7 @@ class Task extends WindowContainer<WindowContainer> { return toString(); } - @Override - public void dumpDebug(ProtoOutputStream proto, long fieldId, + void dumpDebugInner(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { return; @@ -3205,13 +3556,13 @@ class Task extends WindowContainer<WindowContainer> { Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, ActivityStack stack) { - return new Task(service, taskId, info, intent, voiceSession, voiceInteractor, + return new ActivityStack(service, taskId, info, intent, voiceSession, voiceInteractor, null /*taskDescription*/, stack); } Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info, Intent intent, TaskDescription taskDescription, ActivityStack stack) { - return new Task(service, taskId, info, intent, null /*voiceSession*/, + return new ActivityStack(service, taskId, info, intent, null /*voiceSession*/, null /*voiceInteractor*/, taskDescription, stack); } @@ -3228,7 +3579,7 @@ class Task extends WindowContainer<WindowContainer> { int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) { - return new Task(service, taskId, intent, affinityIntent, affinity, + return new ActivityStack(service, taskId, intent, affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation, @@ -3470,7 +3821,9 @@ class Task extends WindowContainer<WindowContainer> { } boolean isControlledByTaskOrganizer() { - return mTaskOrganizer != null; + // TODO(b/147849315): Clean-up relationship between task-org and task-hierarchy. Ideally + // we only give control of the root task. + return getTopMostTask().mTaskOrganizer != null; } @Override @@ -3546,13 +3899,16 @@ class Task extends WindowContainer<WindowContainer> { public void setWindowingMode(int windowingMode) { super.setWindowingMode(windowingMode); windowingMode = getWindowingMode(); - /* - * Different windowing modes may be managed by different task organizers. If - * getTaskOrganizer returns null, we still call transferToTaskOrganizer to - * make sure we clear it. - */ - final ITaskOrganizer org = - mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode); - setTaskOrganizer(org); + + // TODO(b/147849315): Clean-up relationship between task-org and task-hierarchy. Ideally + // we only give control of the root task. + // Different windowing modes may be managed by different task organizers. If + // getTaskOrganizer returns null, we still call transferToTaskOrganizer to make sure we + // clear it. + if (!isRootTask()) { + final ITaskOrganizer org = + mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode); + setTaskOrganizer(org); + } } } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index e2a21a9e9db4..57de7536409f 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -55,6 +55,7 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.GraphicBuffer; import android.graphics.Paint; +import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; import android.os.Looper; @@ -115,6 +116,7 @@ class TaskSnapshotSurface implements StartingSurface { private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM; private static final int MSG_REPORT_DRAW = 0; private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s"; + private static final Point sSurfaceSize = new Point(); //tmp var for unused relayout param private final Window mWindow; private final Surface mSurface; private SurfaceControl mSurfaceControl; @@ -227,7 +229,8 @@ class TaskSnapshotSurface implements StartingSurface { try { session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1, tmpFrame, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, - tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState); + tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState, + sSurfaceSize); } catch (RemoteException e) { // Local call. } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index a43f595e4a9f..1c876d9cc02f 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2249,4 +2249,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< void setSurfaceControl(SurfaceControl sc) { mSurfaceControl = sc; } + + /** Cheap way of doing cast and instanceof. */ + Task asTask() { + return null; + } + + /** Cheap way of doing cast and instanceof. */ + ActivityRecord asActivityRecord() { + return null; + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 77d755d6f36d..92cb948875ab 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2039,7 +2039,8 @@ public class WindowManagerService extends IWindowManager.Stub long frameNumber, Rect outFrame, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration, - SurfaceControl outSurfaceControl, InsetsState outInsetsState) { + SurfaceControl outSurfaceControl, InsetsState outInsetsState, + Point outSurfaceSize) { int result = 0; boolean configChanged; final int pid = Binder.getCallingPid(); @@ -2361,6 +2362,10 @@ public class WindowManagerService extends IWindowManager.Stub displayContent.sendNewConfiguration(); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } + if (winAnimator.mSurfaceController != null) { + outSurfaceSize.set(winAnimator.mSurfaceController.getWidth(), + winAnimator.mSurfaceController.getHeight()); + } } Binder.restoreCallingIdentity(origId); @@ -2414,8 +2419,8 @@ public class WindowManagerService extends IWindowManager.Stub return focusMayChange; } - private int createSurfaceControl(SurfaceControl outSurfaceControl, int result, WindowState win, - WindowStateAnimator winAnimator) { + private int createSurfaceControl(SurfaceControl outSurfaceControl, + int result, WindowState win, WindowStateAnimator winAnimator) { if (!win.mHasSurface) { result |= RELAYOUT_RES_SURFACE_CHANGED; } @@ -2694,8 +2699,7 @@ public class WindowManagerService extends IWindowManager.Stub displayContent.getDockedDividerController().checkMinimizeChanged(animate); } - boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) { - final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + boolean isValidPictureInPictureAspectRatio(DisplayContent displayContent, float aspectRatio) { return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio( aspectRatio); } @@ -2767,7 +2771,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null && mRoot.getTopChild() != displayContent) { - mRoot.positionChildAt(WindowContainer.POSITION_TOP, displayContent, + displayContent.positionDisplayAt(WindowContainer.POSITION_TOP, true /* includingParents */); } } @@ -7694,7 +7698,7 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayContent displayContent = touchedWindow.getDisplayContent(); if (!displayContent.isOnTop()) { - displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent, + displayContent.positionDisplayAt(WindowContainer.POSITION_TOP, true /* includingParents */); } handleTaskFocusChange(touchedWindow.getTask()); diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 2a1e980dfb3d..43cd66dc0616 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; @@ -38,7 +39,9 @@ import android.annotation.CallSuper; import android.os.Debug; import android.os.IBinder; import android.util.proto.ProtoOutputStream; +import android.view.SurfaceControl; +import com.android.server.policy.WindowManagerPolicy; import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; @@ -228,12 +231,6 @@ class WindowToken extends WindowContainer<WindowState> { return false; } - ActivityRecord asActivityRecord() { - // TODO: Not sure if this is the best way to handle this vs. using instanceof and casting. - // I am not an app window token! - return null; - } - @Override void removeImmediately() { if (mDisplayContent != null) { @@ -256,6 +253,27 @@ class WindowToken extends WindowContainer<WindowState> { super.onDisplayChanged(dc); } + @Override + void assignLayer(SurfaceControl.Transaction t, int layer) { + if (windowType == TYPE_DOCK_DIVIDER) { + // See {@link DisplayContent#mSplitScreenDividerAnchor} + super.assignRelativeLayer(t, mDisplayContent.getSplitScreenDividerAnchor(), 1); + } else if (mRoundedCornerOverlay) { + super.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1); + } else { + super.assignLayer(t, layer); + } + } + + @Override + SurfaceControl.Builder makeSurface() { + final SurfaceControl.Builder builder = super.makeSurface(); + if (mRoundedCornerOverlay) { + builder.setParent(null); + } + return builder; + } + @CallSuper @Override public void dumpDebug(ProtoOutputStream proto, long fieldId, @@ -315,4 +333,8 @@ class WindowToken extends WindowContainer<WindowState> { mOwnerCanManageAppTokens); return mOwnerCanManageAppTokens && (layer > navLayer); } + + int getWindowLayerFromType() { + return mWmService.mPolicy.getWindowLayerFromTypeLw(windowType, mOwnerCanManageAppTokens); + } } diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index 2510b60955d3..ec56e1ebc8e0 100644 --- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -131,6 +131,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import org.mockito.InOrder; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -2339,6 +2340,85 @@ public class KeyValueBackupTaskTest { assertThat(mBackupManagerService.getCurrentToken()).isEqualTo(0L); } + /** Do not inform transport of an empty backup if the app hasn't backed up before */ + @Test + public void testRunTask_whenNoDataToBackupOnFirstBackup_doesNotTellTransportOfBackup() + throws Exception { + TransportMock transportMock = setUpInitializedTransport(mTransport); + mBackupManagerService.setCurrentToken(0L); + when(transportMock.transport.getCurrentRestoreSet()).thenReturn(1234L); + setUpAgent(PACKAGE_1); + KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1); + + runTask(task); + + verify(transportMock.transport, never()) + .performBackup( + argThat(packageInfo(PACKAGE_1)), any(ParcelFileDescriptor.class), anyInt()); + } + + /** Let the transport know if there are no changes for a KV backed-up package. */ + @Test + public void testRunTask_whenBackupHasCompletedAndThenNoDataChanges_transportGetsNotified() + throws Exception { + TransportMock transportMock = setUpInitializedTransport(mTransport); + when(transportMock.transport.getCurrentRestoreSet()).thenReturn(1234L); + when(transportMock.transport.isAppEligibleForBackup( + argThat(packageInfo(PACKAGE_1)), eq(false))) + .thenReturn(true); + when(transportMock.transport.isAppEligibleForBackup( + argThat(packageInfo(PACKAGE_2)), eq(false))) + .thenReturn(true); + setUpAgentWithData(PACKAGE_1); + setUpAgentWithData(PACKAGE_2); + + PackageInfo endSentinel = new PackageInfo(); + endSentinel.packageName = KeyValueBackupTask.NO_DATA_END_SENTINEL; + + // Perform First Backup run, which should backup both packages + KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2); + runTask(task); + InOrder order = Mockito.inOrder(transportMock.transport); + order.verify(transportMock.transport) + .performBackup( + argThat(packageInfo(PACKAGE_1)), + any(), + eq(BackupTransport.FLAG_NON_INCREMENTAL)); + order.verify(transportMock.transport).finishBackup(); + order.verify(transportMock.transport) + .performBackup( + argThat(packageInfo(PACKAGE_2)), + any(), + eq(BackupTransport.FLAG_NON_INCREMENTAL)); + order.verify(transportMock.transport).finishBackup(); + + // Run again with new data for package 1, but nothing new for package 2 + task = createKeyValueBackupTask(transportMock, PACKAGE_1); + runTask(task); + + // Now for the second run we performed one incremental backup (package 1) and + // made one "no change" call (package 2) before sending the end sentinel. + order.verify(transportMock.transport) + .performBackup( + argThat(packageInfo(PACKAGE_1)), + any(), + eq(BackupTransport.FLAG_INCREMENTAL)); + order.verify(transportMock.transport).finishBackup(); + order.verify(transportMock.transport) + .performBackup( + argThat(packageInfo(PACKAGE_2)), + any(), + eq(BackupTransport.FLAG_DATA_NOT_CHANGED)); + order.verify(transportMock.transport).finishBackup(); + order.verify(transportMock.transport) + .performBackup( + argThat(packageInfo(endSentinel)), + any(), + eq(BackupTransport.FLAG_DATA_NOT_CHANGED)); + order.verify(transportMock.transport).finishBackup(); + order.verifyNoMoreInteractions(); + } + private void runTask(KeyValueBackupTask task) { // Pretend we are not on the main-thread to prevent RemoteCall from complaining mShadowMainLooper.setCurrentThread(false); @@ -2576,6 +2656,20 @@ public class KeyValueBackupTaskTest { packageInfo != null && packageData.packageName.equals(packageInfo.packageName); } + /** Matches {@link PackageInfo} whose package name is {@code packageData.packageName}. */ + private static ArgumentMatcher<PackageInfo> packageInfo(PackageInfo packageData) { + // We have to test for packageInfo nulity because of Mockito's own stubbing with argThat(). + // E.g. if you do: + // + // 1. when(object.method(argThat(str -> str.equals("foo")))).thenReturn(0) + // 2. when(object.method(argThat(str -> str.equals("bar")))).thenReturn(2) + // + // The second line will throw NPE because it will call lambda 1 with null, since argThat() + // returns null. So we guard against that by checking for null. + return packageInfo -> + packageInfo != null && packageInfo.packageName.equals(packageInfo.packageName); + } + /** Matches {@link ApplicationInfo} whose package name is {@code packageData.packageName}. */ private static ArgumentMatcher<ApplicationInfo> applicationInfo(PackageData packageData) { return applicationInfo -> diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index ad63d078fa67..c60ca48f0b3d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -123,13 +123,13 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testStackCleanupOnClearingTask() { mActivity.onParentChanged(null /*newParent*/, mActivity.getTask()); - verify(mStack, times(1)).onActivityRemovedFromStack(any()); + verify(mStack, times(1)).cleanUpActivityReferences(any()); } @Test public void testStackCleanupOnActivityRemoval() { mTask.removeChild(mActivity); - verify(mStack, times(1)).onActivityRemovedFromStack(any()); + verify(mStack, times(1)).cleanUpActivityReferences(any()); } @Test @@ -141,10 +141,9 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testNoCleanupMovingActivityInSameStack() { - final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack) - .build(); + final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build(); mActivity.reparent(newTask, 0, null /*reason*/); - verify(mStack, times(0)).onActivityRemovedFromStack(any()); + verify(mStack, times(0)).cleanUpActivityReferences(any()); } @Test @@ -490,7 +489,7 @@ public class ActivityRecordTests extends ActivityTestsBase { final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); try { - doReturn(false).when(stack).isStackTranslucent(any()); + doReturn(false).when(stack).isTranslucent(any()); assertFalse(mStack.shouldBeVisible(null /* starting */)); mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), @@ -613,8 +612,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Sending 'null' for saved state can only happen due to timeout, so previously stored saved // states should not be overridden. mActivity.setState(STOPPING, "test"); - mActivity.activityStopped(null /* savedState */, null /* persistentSavedState */, - "desc"); + mActivity.activityStopped(null /* savedState */, null /* persistentSavedState */, "desc"); assertTrue(mActivity.hasSavedState()); assertEquals(savedState, mActivity.getSavedState()); assertEquals(persistentSavedState, mActivity.getPersistentSavedState()); @@ -1013,7 +1011,9 @@ public class ActivityRecordTests extends ActivityTestsBase { public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() { // Empty the home stack. final ActivityStack homeStack = mActivity.getDisplay().getHomeStack(); - homeStack.forAllTasks((t) -> { homeStack.removeChild(t, "test"); }); + homeStack.forAllTasks((t) -> { + homeStack.removeChild(t, "test"); + }, true /* traverseTopToBottom */, homeStack); mActivity.finishing = true; doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities(); spyOn(mStack); @@ -1037,7 +1037,9 @@ public class ActivityRecordTests extends ActivityTestsBase { public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() { // Empty the home stack. final ActivityStack homeStack = mActivity.getDisplay().getHomeStack(); - homeStack.forAllTasks((t) -> { homeStack.removeChild(t, "test"); }); + homeStack.forAllTasks((t) -> { + homeStack.removeChild(t, "test"); + }, true /* traverseTopToBottom */, homeStack); mActivity.finishing = true; spyOn(mStack); @@ -1143,7 +1145,7 @@ public class ActivityRecordTests extends ActivityTestsBase { assertNull(mActivity.app); assertNull(mActivity.getTask()); assertEquals(0, task.getChildCount()); - assertNull(task.getStack()); + assertEquals(task.getStack(), task); assertEquals(0, stack.getChildCount()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index a5157fe98daf..393d8b83cad2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -313,13 +313,13 @@ public class ActivityStackTests extends ActivityTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Home stack shouldn't be visible behind an opaque fullscreen stack, but pinned stack // should be visible since it is always on-top. - doReturn(false).when(fullscreenStack).isStackTranslucent(any()); + doReturn(false).when(fullscreenStack).isTranslucent(any()); assertFalse(homeStack.shouldBeVisible(null /* starting */)); assertTrue(pinnedStack.shouldBeVisible(null /* starting */)); assertTrue(fullscreenStack.shouldBeVisible(null /* starting */)); // Home stack should be visible behind a translucent fullscreen stack. - doReturn(true).when(fullscreenStack).isStackTranslucent(any()); + doReturn(true).when(fullscreenStack).isTranslucent(any()); assertTrue(homeStack.shouldBeVisible(null /* starting */)); assertTrue(pinnedStack.shouldBeVisible(null /* starting */)); } @@ -338,8 +338,8 @@ public class ActivityStackTests extends ActivityTestsBase { WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Home stack shouldn't be visible if both halves of split-screen are opaque. - doReturn(false).when(splitScreenPrimary).isStackTranslucent(any()); - doReturn(false).when(splitScreenSecondary).isStackTranslucent(any()); + doReturn(false).when(splitScreenPrimary).isTranslucent(any()); + doReturn(false).when(splitScreenSecondary).isTranslucent(any()); assertFalse(homeStack.shouldBeVisible(null /* starting */)); assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); @@ -350,7 +350,7 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary.getVisibility(null /* starting */)); // Home stack should be visible if one of the halves of split-screen is translucent. - doReturn(true).when(splitScreenPrimary).isStackTranslucent(any()); + doReturn(true).when(splitScreenPrimary).isTranslucent(any()); assertTrue(homeStack.shouldBeVisible(null /* starting */)); assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); @@ -366,7 +366,7 @@ public class ActivityStackTests extends ActivityTestsBase { WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); // First split-screen secondary shouldn't be visible behind another opaque split-split // secondary. - doReturn(false).when(splitScreenSecondary2).isStackTranslucent(any()); + doReturn(false).when(splitScreenSecondary2).isTranslucent(any()); assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */)); assertEquals(STACK_VISIBILITY_INVISIBLE, @@ -376,7 +376,7 @@ public class ActivityStackTests extends ActivityTestsBase { // First split-screen secondary should be visible behind another translucent split-screen // secondary. - doReturn(true).when(splitScreenSecondary2).isStackTranslucent(any()); + doReturn(true).when(splitScreenSecondary2).isTranslucent(any()); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */)); assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, @@ -388,7 +388,7 @@ public class ActivityStackTests extends ActivityTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */); // Split-screen stacks shouldn't be visible behind an opaque fullscreen stack. - doReturn(false).when(assistantStack).isStackTranslucent(any()); + doReturn(false).when(assistantStack).isTranslucent(any()); assertTrue(assistantStack.shouldBeVisible(null /* starting */)); assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */)); @@ -403,7 +403,7 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary2.getVisibility(null /* starting */)); // Split-screen stacks should be visible behind a translucent fullscreen stack. - doReturn(true).when(assistantStack).isStackTranslucent(any()); + doReturn(true).when(assistantStack).isTranslucent(any()); assertTrue(assistantStack.shouldBeVisible(null /* starting */)); assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); @@ -418,9 +418,9 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary2.getVisibility(null /* starting */)); // Assistant stack shouldn't be visible behind translucent split-screen stack - doReturn(false).when(assistantStack).isStackTranslucent(any()); - doReturn(true).when(splitScreenPrimary).isStackTranslucent(any()); - doReturn(true).when(splitScreenSecondary2).isStackTranslucent(any()); + doReturn(false).when(assistantStack).isTranslucent(any()); + doReturn(true).when(splitScreenPrimary).isTranslucent(any()); + doReturn(true).when(splitScreenSecondary2).isTranslucent(any()); splitScreenSecondary2.moveToFront("testShouldBeVisible_SplitScreen"); splitScreenPrimary.moveToFront("testShouldBeVisible_SplitScreen"); assertFalse(assistantStack.shouldBeVisible(null /* starting */)); @@ -555,7 +555,7 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityStack translucentStack = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - doReturn(true).when(translucentStack).isStackTranslucent(any()); + doReturn(true).when(translucentStack).isTranslucent(any()); assertTrue(homeStack.shouldBeVisible(null /* starting */)); assertTrue(translucentStack.shouldBeVisible(null /* starting */)); @@ -603,8 +603,8 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - doReturn(false).when(homeStack).isStackTranslucent(any()); - doReturn(false).when(fullscreenStack).isStackTranslucent(any()); + doReturn(false).when(homeStack).isTranslucent(any()); + doReturn(false).when(fullscreenStack).isTranslucent(any()); // Ensure that we don't move the home stack if it is already behind the top fullscreen stack int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); @@ -622,8 +622,8 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - doReturn(false).when(homeStack).isStackTranslucent(any()); - doReturn(true).when(fullscreenStack).isStackTranslucent(any()); + doReturn(false).when(homeStack).isTranslucent(any()); + doReturn(true).when(fullscreenStack).isTranslucent(any()); // Ensure that we don't move the home stack if it is already behind the top fullscreen stack int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); @@ -641,8 +641,8 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - doReturn(false).when(homeStack).isStackTranslucent(any()); - doReturn(false).when(fullscreenStack).isStackTranslucent(any()); + doReturn(false).when(homeStack).isTranslucent(any()); + doReturn(false).when(fullscreenStack).isTranslucent(any()); // Ensure we don't move the home stack if it is already on top int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); @@ -666,9 +666,9 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); - doReturn(false).when(homeStack).isStackTranslucent(any()); - doReturn(false).when(fullscreenStack1).isStackTranslucent(any()); - doReturn(false).when(fullscreenStack2).isStackTranslucent(any()); + doReturn(false).when(homeStack).isTranslucent(any()); + doReturn(false).when(fullscreenStack1).isTranslucent(any()); + doReturn(false).when(fullscreenStack2).isTranslucent(any()); // Ensure that we move the home stack behind the bottom most fullscreen stack, ignoring the // pinned stack @@ -691,9 +691,9 @@ public class ActivityStackTests extends ActivityTestsBase { mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - doReturn(false).when(homeStack).isStackTranslucent(any()); - doReturn(false).when(fullscreenStack1).isStackTranslucent(any()); - doReturn(true).when(fullscreenStack2).isStackTranslucent(any()); + doReturn(false).when(homeStack).isTranslucent(any()); + doReturn(false).when(fullscreenStack1).isTranslucent(any()); + doReturn(true).when(fullscreenStack2).isTranslucent(any()); // Ensure that we move the home stack behind the bottom most non-translucent fullscreen // stack @@ -715,9 +715,9 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - doReturn(false).when(homeStack).isStackTranslucent(any()); - doReturn(false).when(fullscreenStack1).isStackTranslucent(any()); - doReturn(false).when(fullscreenStack2).isStackTranslucent(any()); + doReturn(false).when(homeStack).isTranslucent(any()); + doReturn(false).when(fullscreenStack1).isTranslucent(any()); + doReturn(false).when(fullscreenStack2).isTranslucent(any()); // Ensure we don't move the home stack behind itself int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); @@ -810,9 +810,9 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */); - doReturn(false).when(splitScreenPrimary).isStackTranslucent(any()); - doReturn(false).when(splitScreenSecondary).isStackTranslucent(any()); - doReturn(false).when(assistantStack).isStackTranslucent(any()); + doReturn(false).when(splitScreenPrimary).isTranslucent(any()); + doReturn(false).when(splitScreenSecondary).isTranslucent(any()); + doReturn(false).when(assistantStack).isTranslucent(any()); assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */)); @@ -829,7 +829,7 @@ public class ActivityStackTests extends ActivityTestsBase { boolean translucent) { final ActivityStack stack = createStackForShouldBeVisibleTest(mDefaultDisplay, windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */); - doReturn(translucent).when(stack).isStackTranslucent(any()); + doReturn(translucent).when(stack).isTranslucent(any()); return stack; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 4beede93aea2..eb84d0af35c7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -375,7 +375,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { intent.setComponent(mComponent); intent.setFlags(mFlags); - final Task task = new Task(mSupervisor.mService, mTaskId, aInfo, + final Task task = new ActivityStack(mSupervisor.mService, mTaskId, aInfo, intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/, null /*taskDescription*/, mStack); spyOn(task); @@ -398,6 +398,8 @@ class ActivityTestsBase extends SystemServiceTestsBase { private int mActivityType = ACTIVITY_TYPE_STANDARD; private boolean mOnTop = true; private boolean mCreateActivity = true; + private ActivityInfo mInfo; + private Intent mIntent; StackBuilder(RootWindowContainer root) { mRootWindowContainer = root; @@ -434,13 +436,22 @@ class ActivityTestsBase extends SystemServiceTestsBase { return this; } + StackBuilder setActivityInfo(ActivityInfo info) { + mInfo = info; + return this; + } + + StackBuilder setIntent(Intent intent) { + mIntent = intent; + return this; + } + ActivityStack build() { final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId(); - final ActivityStack stack; + final ActivityStack stack = mDisplay.createStackUnchecked(mWindowingMode, + mActivityType, stackId, mOnTop, mInfo, mIntent); final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor; - stack = mDisplay.createStackUnchecked(mWindowingMode, mActivityType, stackId, mOnTop); - if (mCreateActivity) { new ActivityBuilder(supervisor.mService) .setCreateTask(true) diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index 9562fa41a4b7..fa0485c8678b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -152,6 +152,8 @@ public class TaskRecordTests extends ActivityTestsBase { @Test public void testReturnsToHomeStack() throws Exception { final Task task = createTask(1); + spyOn(task); + doReturn(true).when(task).hasChild(); assertFalse(task.returnsToHomeStack()); task.intent = null; assertFalse(task.returnsToHomeStack()); @@ -906,7 +908,7 @@ public class TaskRecordTests extends ActivityTestsBase { } private Task createTask(int taskId) { - return new Task(mService, taskId, new Intent(), null, null, null, + return new ActivityStack(mService, taskId, new Intent(), null, null, null, ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null, 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0, 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/, diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java index b4f5751a6ca2..6e4be88a31fe 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java @@ -115,7 +115,7 @@ public class TaskStackTests extends WindowTestsBase { // Remove stack and check if its child is also removed. stack.removeImmediately(); assertNull(stack.getDisplayContent()); - assertNull(task.getStack()); + assertNull(task.getParent()); } @Test @@ -131,7 +131,7 @@ public class TaskStackTests extends WindowTestsBase { assertEquals(0, stack.getChildCount()); assertNull(stack.getDisplayContent()); assertNull(task.getDisplayContent()); - assertNull(task.getStack()); + assertNull(task.getParent()); } @Test @@ -140,6 +140,7 @@ public class TaskStackTests extends WindowTestsBase { final Task task = createTaskInStack(stack, 0 /* userId */); // Stack removal is deferred if one of its child is animating. + doReturn(true).when(stack).hasWindowsAlive(); doReturn(true).when(task).isAnimating(TRANSITION | CHILDREN); stack.removeIfPossible(); diff --git a/wifi/Android.bp b/wifi/Android.bp index 5ef892d005ac..099cbff15fb4 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -58,19 +58,20 @@ test_access_hidden_api_whitelist = [ // classes before they are renamed. java_library { name: "framework-wifi-pre-jarjar", - // TODO(b/140299412) should be core_current once we build against framework-system-stubs - sdk_version: "core_platform", + // TODO(b/146757305): sdk_version should be "module_lib_current" + sdk_version: "core_current", static_libs: [ "framework-wifi-util-lib", "android.hardware.wifi-V1.0-java-constants", ], libs: [ - // TODO(b/140299412) should be framework-system-stubs once we fix all @hide dependencies - "framework-minus-apex", "framework-annotations-lib", "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage "unsupportedappusage-annotation", // for dalvik.annotation.compat.UnsupportedAppUsage "framework-telephony-stubs", + // TODO(b/146757305): should be unnecessary once + // sdk_version="module_lib_current" + "android_system_stubs_current", ], srcs: [ ":framework-wifi-updatable-sources", @@ -80,13 +81,21 @@ java_library { "//frameworks/opt/net/wifi/service", "//frameworks/opt/net/wifi/tests/wifitests", ], + + // TODO(b/146757305): should be unnecessary once + // sdk_version="module_lib_current" + aidl: { + include_dirs: [ + "frameworks/base/core/java", + ], + }, } // post-jarjar version of framework-wifi java_library { name: "framework-wifi", - // TODO(b/140299412) should be core_current once we build against framework-system-stubs - sdk_version: "core_platform", + // TODO(b/146757305): sdk_version should be "module_lib_current" + sdk_version: "core_current", static_libs: [ "framework-wifi-pre-jarjar", ], @@ -98,7 +107,6 @@ java_library { }, hostdex: true, // for hiddenapi check visibility: [ - "//frameworks/base", // TODO(b/140299412) remove once all dependencies are fixed "//frameworks/opt/net/wifi/service:__subpackages__", ] + test_access_hidden_api_whitelist, apex_available: [ diff --git a/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl index d14ec57ea07a..51d74f0fcfa9 100644 --- a/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl +++ b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl @@ -17,7 +17,6 @@ package android.net.wifi; import android.net.wifi.INetworkRequestUserSelectionCallback; -import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; /** @@ -31,7 +30,7 @@ oneway interface INetworkRequestMatchCallback void onAbort(); - void onMatch(in List<ScanResult> scanResults); + void onMatch(in List<android.net.wifi.ScanResult> scanResults); void onUserSelectionConnectSuccess(in WifiConfiguration wificonfiguration); diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index dafb4de62f3c..0b5969a8999d 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -36,7 +36,6 @@ import android.net.wifi.ISuggestionConnectionStatusListener; import android.net.wifi.ITrafficStateCallback; import android.net.wifi.ITxPacketCountListener; import android.net.wifi.IWifiConnectedNetworkScorer; -import android.net.wifi.ScanResult; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; @@ -61,9 +60,9 @@ interface IWifiManager ParceledListSlice getPrivilegedConfiguredNetworks(String packageName, String featureId); - Map getAllMatchingFqdnsForScanResults(in List<ScanResult> scanResult); + Map getAllMatchingFqdnsForScanResults(in List<android.net.wifi.ScanResult> scanResult); - Map getMatchingOsuProviders(in List<ScanResult> scanResult); + Map getMatchingOsuProviders(in List<android.net.wifi.ScanResult> scanResult); Map getMatchingPasspointConfigsForOsuProviders(in List<OsuProvider> osuProviders); @@ -97,7 +96,7 @@ interface IWifiManager boolean startScan(String packageName, String featureId); - List<ScanResult> getScanResults(String callingPackage, String callingFeatureId); + List<android.net.wifi.ScanResult> getScanResults(String callingPackage, String callingFeatureId); boolean disconnect(String packageName); @@ -256,7 +255,7 @@ interface IWifiManager int calculateSignalLevel(int rssi); - List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(in List<ScanResult> scanResults); + List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(in List<android.net.wifi.ScanResult> scanResults); boolean setWifiConnectedNetworkScorer(in IBinder binder, in IWifiConnectedNetworkScorer scorer); diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java index 0cf0c22d8dc2..6085eae252ef 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java +++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java @@ -692,12 +692,14 @@ public final class WifiNetworkSuggestion implements Parcelable { * Network configuration for the provided network. * @hide */ + @NonNull public final WifiConfiguration wifiConfiguration; /** * Passpoint configuration for the provided network. * @hide */ + @Nullable public final PasspointConfiguration passpointConfiguration; /** @@ -734,7 +736,7 @@ public final class WifiNetworkSuggestion implements Parcelable { /** @hide */ public WifiNetworkSuggestion() { - this.wifiConfiguration = null; + this.wifiConfiguration = new WifiConfiguration(); this.passpointConfiguration = null; this.isAppInteractionRequired = false; this.isUserInteractionRequired = false; @@ -842,4 +844,25 @@ public final class WifiNetworkSuggestion implements Parcelable { .append(" ]"); return sb.toString(); } + + /** + * Get the {@link WifiConfiguration} associated with this Suggestion. + * @hide + */ + @SystemApi + @NonNull + public WifiConfiguration getWifiConfiguration() { + return wifiConfiguration; + } + + /** + * Get the {@link PasspointConfiguration} associated with this Suggestion, or null if this + * Suggestion is not for a Passpoint network. + * @hide + */ + @SystemApi + @Nullable + public PasspointConfiguration getPasspointConfiguration() { + return passpointConfiguration; + } } |