diff options
17 files changed, 498 insertions, 140 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 463d0c49f72d..fccb3c0146cf 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1026,6 +1026,7 @@ package android.graphics { } public class Typeface { + method @NonNull public static android.util.Pair<java.util.List<android.graphics.Typeface>,java.util.List<android.graphics.Typeface>> changeDefaultFontForTest(@NonNull java.util.List<android.graphics.Typeface>, @NonNull java.util.List<android.graphics.Typeface>); method @NonNull public static long[] deserializeFontMap(@NonNull java.nio.ByteBuffer, @NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws java.io.IOException; method @Nullable public static android.os.SharedMemory getSystemFontMapSharedMemory(); method @NonNull public static android.os.SharedMemory serializeFontMap(@NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws android.system.ErrnoException, java.io.IOException; diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index e02d323f7d74..eb8b8603cc30 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -106,7 +106,10 @@ interface IInputMethodManager { /** Remove the IME surface. Requires passing the currently focused window. */ oneway void removeImeSurfaceFromWindowAsync(in IBinder windowToken); + + @JavaPassthrough(annotation="@android.annotation.RequiresNoPermission") void startProtoDump(in byte[] protoDump, int source, String where); + boolean isImeTraceEnabled(); // Starts an ime trace. diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 596d0617e265..f4f5e1e792ec 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -50,6 +50,7 @@ import android.util.Base64; import android.util.Log; import android.util.LongSparseArray; import android.util.LruCache; +import android.util.Pair; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; @@ -1396,6 +1397,41 @@ public class Typeface { } } + /** + * Change default typefaces for testing purpose. + * + * Note: The existing TextView or Paint instance still holds the old Typeface. + * + * @param defaults array of [default, default_bold, default_italic, default_bolditalic]. + * @param genericFamilies array of [sans-serif, serif, monospace] + * @return return the old defaults and genericFamilies + * @hide + */ + @TestApi + @NonNull + public static Pair<List<Typeface>, List<Typeface>> changeDefaultFontForTest( + @NonNull List<Typeface> defaults, + @NonNull List<Typeface> genericFamilies + ) { + synchronized (SYSTEM_FONT_MAP_LOCK) { + List<Typeface> oldDefaults = Arrays.asList(sDefaults); + sDefaults = defaults.toArray(new Typeface[4]); + setDefault(defaults.get(0)); + + ArrayList<Typeface> oldGenerics = new ArrayList<>(); + oldGenerics.add(sSystemFontMap.get("sans-serif")); + sSystemFontMap.put("sans-serif", genericFamilies.get(0)); + + oldGenerics.add(sSystemFontMap.get("serif")); + sSystemFontMap.put("serif", genericFamilies.get(1)); + + oldGenerics.add(sSystemFontMap.get("monospace")); + sSystemFontMap.put("monospace", genericFamilies.get(2)); + + return new Pair<>(oldDefaults, oldGenerics); + } + } + static { // Preload Roboto-Regular.ttf in Zygote for improving app launch performance. preloadFontFile("/system/fonts/Roboto-Regular.ttf"); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index 913e4b7afeeb..1155ea174ed1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -445,7 +445,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // When exit to fullscreen with Shell transition enabled, we update the Task windowing // mode directly so that it can also trigger display rotation and visibility update in // the same transition if there will be any. - wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); + wct.setWindowingMode(mToken, getOutPipWindowingMode()); // We can inherit the parent bounds as it is going to be fullscreen. The // destinationBounds calculated above will be incorrect if this is with rotation. wct.setBounds(mToken, null); @@ -544,7 +544,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, if (Transitions.ENABLE_SHELL_TRANSITIONS) { final WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mToken, null); - wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); + wct.setWindowingMode(mToken, getOutPipWindowingMode()); wct.reorder(mToken, false); mPipTransitionController.startExitTransition(TRANSIT_REMOVE_PIP, wct, null /* destinationBounds */); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 53ec39d954c4..63f55c49851b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -352,41 +352,31 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent, @SplitPosition int position, @Nullable Bundle options) { + if (fillInIntent == null) { + fillInIntent = new Intent(); + } + // Flag this as a no-user-action launch to prevent sending user leaving event to the + // current top activity since it's going to be put into another side of the split. This + // prevents the current top activity from going into pip mode due to user leaving event. + fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION); + + // Flag with MULTIPLE_TASK if this is launching the same activity into both sides of the + // split. + if (isLaunchingAdjacently(intent.getIntent(), position)) { + fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK"); + } + if (!ENABLE_SHELL_TRANSITIONS) { startIntentLegacy(intent, fillInIntent, position, options); return; } - try { - options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, - null /* wct */); - - if (fillInIntent == null) { - fillInIntent = new Intent(); - } - // Flag this as a no-user-action launch to prevent sending user leaving event to the - // current top activity since it's going to be put into another side of the split. This - // prevents the current top activity from going into pip mode due to user leaving event. - fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION); - - // Flag with MULTIPLE_TASK if this is launching the same activity into both sides of the - // split. - if (isLaunchingAdjacently(intent.getIntent(), position)) { - fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK"); - } - - intent.send(mContext, 0, fillInIntent, null /* onFinished */, null /* handler */, - null /* requiredPermission */, options); - } catch (PendingIntent.CanceledException e) { - Slog.e(TAG, "Failed to launch task", e); - } + mStageCoordinator.startIntent(intent, fillInIntent, position, options); } - private void startIntentLegacy(PendingIntent intent, @Nullable Intent fillInIntent, + private void startIntentLegacy(PendingIntent intent, Intent fillInIntent, @SplitPosition int position, @Nullable Bundle options) { - boolean startSameActivityAdjacently = isLaunchingAdjacently(intent.getIntent(), position); - final WindowContainerTransaction evictWct = new WindowContainerTransaction(); mStageCoordinator.prepareEvictChildTasks(position, evictWct); @@ -397,8 +387,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, IRemoteAnimationFinishedCallback finishedCallback, SurfaceControl.Transaction t) { if (apps == null || apps.length == 0) { - if (startSameActivityAdjacently) { - // Switch split position if dragging the same activity to another side. + // Switch the split position if launching as MULTIPLE_TASK failed. + if ((fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) { setSideStagePosition(SplitLayout.reversePosition( mStageCoordinator.getSideStagePosition())); } @@ -432,18 +422,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, final WindowContainerTransaction wct = new WindowContainerTransaction(); options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct); - // Flag this as a no-user-action launch to prevent sending user leaving event to the current - // top activity since it's going to be put into another side of the split. This prevents the - // current top activity from going into pip mode due to user leaving event. - if (fillInIntent == null) { - fillInIntent = new Intent(); - } - fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION); - if (startSameActivityAdjacently) { - fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK"); - } - wct.sendPendingIntent(intent, fillInIntent, options); mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java index 056cd5813861..83bdf8bfb727 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java @@ -62,13 +62,12 @@ class SplitScreenTransitions { private final Runnable mOnFinish; DismissTransition mPendingDismiss = null; - IBinder mPendingEnter = null; - IBinder mPendingRecent = null; + TransitSession mPendingEnter = null; + TransitSession mPendingRecent = null; private IBinder mAnimatingTransition = null; OneShotRemoteHandler mPendingRemoteHandler = null; private OneShotRemoteHandler mActiveRemoteHandler = null; - private boolean mEnterTransitionMerged; private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish; @@ -145,7 +144,7 @@ class SplitScreenTransitions { continue; } - if (transition == mPendingEnter && (mainRoot.equals(change.getContainer()) + if (isPendingEnter(transition) && (mainRoot.equals(change.getContainer()) || sideRoot.equals(change.getContainer()))) { t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top); t.setWindowCrop(leash, change.getEndAbsBounds().width(), @@ -171,12 +170,40 @@ class SplitScreenTransitions { onFinish(null /* wct */, null /* wctCB */); } + boolean isPendingTransition(IBinder transition) { + return isPendingEnter(transition) + || isPendingDismiss(transition) + || isPendingRecent(transition); + } + + boolean isPendingEnter(IBinder transition) { + return mPendingEnter != null && mPendingEnter.mTransition == transition; + } + + boolean isPendingRecent(IBinder transition) { + return mPendingRecent != null && mPendingRecent.mTransition == transition; + } + + boolean isPendingDismiss(IBinder transition) { + return mPendingDismiss != null && mPendingDismiss.mTransition == transition; + } + /** Starts a transition to enter split with a remote transition animator. */ - IBinder startEnterTransition(@WindowManager.TransitionType int transitType, - @NonNull WindowContainerTransaction wct, @Nullable RemoteTransition remoteTransition, - @NonNull Transitions.TransitionHandler handler) { + IBinder startEnterTransition( + @WindowManager.TransitionType int transitType, + WindowContainerTransaction wct, + @Nullable RemoteTransition remoteTransition, + Transitions.TransitionHandler handler, + @Nullable TransitionCallback callback) { final IBinder transition = mTransitions.startTransition(transitType, wct, handler); - mPendingEnter = transition; + setEnterTransition(transition, remoteTransition, callback); + return transition; + } + + /** Sets a transition to enter split. */ + void setEnterTransition(@NonNull IBinder transition, + @Nullable RemoteTransition remoteTransition, @Nullable TransitionCallback callback) { + mPendingEnter = new TransitSession(transition, callback); if (remoteTransition != null) { // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff) @@ -184,7 +211,9 @@ class SplitScreenTransitions { mTransitions.getMainExecutor(), remoteTransition); mPendingRemoteHandler.setTransition(transition); } - return transition; + + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition " + + " deduced Enter split screen"); } /** Starts a transition to dismiss split. */ @@ -209,8 +238,8 @@ class SplitScreenTransitions { } void setRecentTransition(@NonNull IBinder transition, - @Nullable RemoteTransition remoteTransition) { - mPendingRecent = transition; + @Nullable RemoteTransition remoteTransition, @Nullable TransitionCallback callback) { + mPendingRecent = new TransitSession(transition, callback); if (remoteTransition != null) { // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff) @@ -226,6 +255,18 @@ class SplitScreenTransitions { void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) { if (mergeTarget != mAnimatingTransition) return; + + if (isPendingEnter(transition) && isPendingRecent(mergeTarget)) { + mPendingRecent.mCallback = new TransitionCallback() { + @Override + public void onTransitionFinished(WindowContainerTransaction finishWct, + SurfaceControl.Transaction finishT) { + // Since there's an entering transition merged, recent transition no longer + // need to handle entering split screen after the transition finished. + } + }; + } + if (mActiveRemoteHandler != null) { mActiveRemoteHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); } else { @@ -247,38 +288,55 @@ class SplitScreenTransitions { } void onTransitionConsumed(@NonNull IBinder transition, boolean aborted) { - if (aborted) return; + if (isPendingEnter(transition)) { + if (!aborted) { + // An enter transition got merged, appends the rest operations to finish entering + // split screen. + // TODO (b/238856352): Passed-in the proper finish transition to merge instead. + if (mFinishTransaction == null) { + mFinishTransaction = mTransactionPool.acquire(); + } + mStageCoordinator.finishEnterSplitScreen(mFinishTransaction); + } - // Once a pending enter transition got merged, make sure to append the reset of finishing - // operations to the finish transition. - if (transition == mPendingEnter) { - mFinishTransaction = mTransactionPool.acquire(); - mStageCoordinator.finishEnterSplitScreen(mFinishTransaction); + mPendingEnter.mCallback.onTransitionConsumed(aborted); mPendingEnter = null; mPendingRemoteHandler = null; - mEnterTransitionMerged = true; + } else if (isPendingDismiss(transition)) { + mPendingDismiss.mCallback.onTransitionConsumed(aborted); + mPendingDismiss = null; + } else if (isPendingRecent(transition)) { + mPendingRecent.mCallback.onTransitionConsumed(aborted); + mPendingRecent = null; + mPendingRemoteHandler = null; } } void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) { if (!mAnimations.isEmpty()) return; - if (mAnimatingTransition == mPendingEnter) { + + TransitionCallback callback = null; + if (isPendingEnter(mAnimatingTransition)) { + callback = mPendingEnter.mCallback; mPendingEnter = null; } - if (mPendingDismiss != null && mPendingDismiss.mTransition == mAnimatingTransition) { + if (isPendingDismiss(mAnimatingTransition)) { + callback = mPendingDismiss.mCallback; mPendingDismiss = null; } - if (mAnimatingTransition == mPendingRecent) { - if (!mEnterTransitionMerged) { - if (wct == null) wct = new WindowContainerTransaction(); - mStageCoordinator.onRecentTransitionFinished(wct, mFinishTransaction); - } + if (isPendingRecent(mAnimatingTransition)) { + callback = mPendingRecent.mCallback; mPendingRecent = null; } + + if (callback != null) { + if (wct == null) wct = new WindowContainerTransaction(); + callback.onTransitionFinished(wct, mFinishTransaction); + } + mPendingRemoteHandler = null; mActiveRemoteHandler = null; mAnimatingTransition = null; - mEnterTransitionMerged = false; mOnFinish.run(); if (mFinishTransaction != null) { @@ -382,17 +440,34 @@ class SplitScreenTransitions { || info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN; } - /** Bundled information of dismiss transition. */ - static class DismissTransition { - IBinder mTransition; + /** Clean-up callbacks for transition. */ + interface TransitionCallback { + /** Calls when the transition got consumed. */ + default void onTransitionConsumed(boolean aborted) {} + + /** Calls when the transition finished. */ + default void onTransitionFinished(WindowContainerTransaction finishWct, + SurfaceControl.Transaction finishT) {} + } - int mReason; + /** Session for a transition and its clean-up callback. */ + static class TransitSession { + final IBinder mTransition; + TransitionCallback mCallback; - @SplitScreen.StageType - int mDismissTop; + TransitSession(IBinder transition, @Nullable TransitionCallback callback) { + mTransition = transition; + mCallback = callback != null ? callback : new TransitionCallback() {}; + } + } + + /** Bundled information of dismiss transition. */ + static class DismissTransition extends TransitSession { + final int mReason; + final @SplitScreen.StageType int mDismissTop; DismissTransition(IBinder transition, int reason, int dismissTop) { - this.mTransition = transition; + super(transition, null /* callback */); this.mReason = reason; this.mDismissTop = dismissTop; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 2229e26b9343..b33a2829bee4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_CHANGE; @@ -214,6 +215,33 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } }; + private final SplitScreenTransitions.TransitionCallback mRecentTransitionCallback = + new SplitScreenTransitions.TransitionCallback() { + @Override + public void onTransitionFinished(WindowContainerTransaction finishWct, + SurfaceControl.Transaction finishT) { + // Check if the recent transition is finished by returning to the current split, so we + // can restore the divider bar. + for (int i = 0; i < finishWct.getHierarchyOps().size(); ++i) { + final WindowContainerTransaction.HierarchyOp op = + finishWct.getHierarchyOps().get(i); + final IBinder container = op.getContainer(); + if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop() + && (mMainStage.containsContainer(container) + || mSideStage.containsContainer(container))) { + setDividerVisibility(true, finishT); + return; + } + } + + // Dismiss the split screen if it's not returning to split. + prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, finishWct); + setSplitsVisible(false); + setDividerVisibility(false, finishT); + logExit(EXIT_REASON_UNKNOWN); + } + }; + StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, ShellTaskOrganizer taskOrganizer, DisplayController displayController, DisplayImeController displayImeController, @@ -337,15 +365,23 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final WindowContainerTransaction evictWct = new WindowContainerTransaction(); targetStage.evictAllChildren(evictWct); targetStage.addTask(task, wct); - if (!evictWct.isEmpty()) { - wct.merge(evictWct, true /* transfer */); - } if (ENABLE_SHELL_TRANSITIONS) { prepareEnterSplitScreen(wct); - mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, - wct, null, this); + mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, + null, this, new SplitScreenTransitions.TransitionCallback() { + @Override + public void onTransitionFinished(WindowContainerTransaction finishWct, + SurfaceControl.Transaction finishT) { + if (!evictWct.isEmpty()) { + finishWct.merge(evictWct, true); + } + } + }); } else { + if (!evictWct.isEmpty()) { + wct.merge(evictWct, true /* transfer */); + } mTaskOrganizer.applyTransaction(wct); } return true; @@ -365,6 +401,39 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return result; } + /** Launches an activity into split. */ + void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position, + @Nullable Bundle options) { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + final WindowContainerTransaction evictWct = new WindowContainerTransaction(); + prepareEvictChildTasks(position, evictWct); + + options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */); + wct.sendPendingIntent(intent, fillInIntent, options); + prepareEnterSplitScreen(wct, null /* taskInfo */, position); + + mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, null, this, + new SplitScreenTransitions.TransitionCallback() { + @Override + public void onTransitionConsumed(boolean aborted) { + // Switch the split position if launching as MULTIPLE_TASK failed. + if (aborted + && (fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) { + setSideStagePositionAnimated( + SplitLayout.reversePosition(mSideStagePosition)); + } + } + + @Override + public void onTransitionFinished(WindowContainerTransaction finishWct, + SurfaceControl.Transaction finishT) { + if (!evictWct.isEmpty()) { + finishWct.merge(evictWct, true); + } + } + }); + } + /** Starts 2 tasks in one transition. */ void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio, @@ -395,7 +464,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, wct.startTask(sideTaskId, sideOptions); mSplitTransitions.startEnterTransition( - TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this); + TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null); } /** Starts 2 tasks in one legacy transition. */ @@ -617,11 +686,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } int getTaskId(@SplitPosition int splitPosition) { - if (mSideStagePosition == splitPosition) { - return mSideStage.getTopVisibleChildTaskId(); - } else { - return mMainStage.getTopVisibleChildTaskId(); + if (splitPosition == SPLIT_POSITION_UNDEFINED) { + return INVALID_TASK_ID; } + + return mSideStagePosition == splitPosition + ? mSideStage.getTopVisibleChildTaskId() + : mMainStage.getTopVisibleChildTaskId(); } void setSideStagePositionAnimated(@SplitPosition int sideStagePosition) { @@ -861,6 +932,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.init(); setDividerVisibility(true, t); updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */); + t.show(mRootTaskLeash); setSplitsVisible(true); mShouldUpdateRecents = true; updateRecentTasksSplitPair(); @@ -1543,14 +1615,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } else if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) { // Enter overview panel, so start recent transition. - mSplitTransitions.setRecentTransition(transition, - request.getRemoteTransition()); + mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(), + mRecentTransitionCallback); } else if (mSplitTransitions.mPendingRecent == null) { // If split-task is not controlled by recents animation // and occluded by the other fullscreen task, dismiss both. prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out); - mSplitTransitions.setDismissTransition(transition, - STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN); + mSplitTransitions.setDismissTransition( + transition, STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN); } } } else { @@ -1558,7 +1630,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // One task is appearing into split, prepare to enter split screen. out = new WindowContainerTransaction(); prepareEnterSplitScreen(out); - mSplitTransitions.mPendingEnter = transition; + mSplitTransitions.setEnterTransition( + transition, request.getRemoteTransition(), null /* callback */); } } return out; @@ -1614,10 +1687,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { - if (transition != mSplitTransitions.mPendingEnter - && transition != mSplitTransitions.mPendingRecent - && (mSplitTransitions.mPendingDismiss == null - || mSplitTransitions.mPendingDismiss.mTransition != transition)) { + if (!mSplitTransitions.isPendingTransition(transition)) { // Not entering or exiting, so just do some house-keeping and validation. // If we're not in split-mode, just abort so something else can handle it. @@ -1664,12 +1734,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } boolean shouldAnimate = true; - if (mSplitTransitions.mPendingEnter == transition) { + if (mSplitTransitions.isPendingEnter(transition)) { shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction); - } else if (mSplitTransitions.mPendingRecent == transition) { + } else if (mSplitTransitions.isPendingRecent(transition)) { shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction); - } else if (mSplitTransitions.mPendingDismiss != null - && mSplitTransitions.mPendingDismiss.mTransition == transition) { + } else if (mSplitTransitions.isPendingDismiss(transition)) { shouldAnimate = startPendingDismissAnimation( mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction); } @@ -1837,28 +1906,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return true; } - void onRecentTransitionFinished(WindowContainerTransaction wct, - SurfaceControl.Transaction finishT) { - // Check if the recent transition is finished by returning to the current split so we can - // restore the divider bar. - for (int i = 0; i < wct.getHierarchyOps().size(); ++i) { - final WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i); - final IBinder container = op.getContainer(); - if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop() - && (mMainStage.containsContainer(container) - || mSideStage.containsContainer(container))) { - setDividerVisibility(true, finishT); - return; - } - } - - // Dismiss the split screen is it's not returning to split. - prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct); - setSplitsVisible(false); - setDividerVisibility(false, finishT); - logExit(EXIT_REASON_UNKNOWN); - } - private void addDividerBarToTransition(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, boolean show) { final SurfaceControl leash = mSplitLayout.getDividerLeash(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index c19a33abf8a4..4855fbd5ba7a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -222,10 +222,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> float shadowRadius = outResult.mDensity * shadowRadiusDp; int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor(); - mTmpColor[0] = Color.red(backgroundColorInt); - mTmpColor[1] = Color.green(backgroundColorInt); - mTmpColor[2] = Color.blue(backgroundColorInt); - t.setCrop(mTaskBackgroundSurface, taskBounds) + mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; + mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; + mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; + t.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height()) .setShadowRadius(mTaskBackgroundSurface, shadowRadius) .setColor(mTaskBackgroundSurface, mTmpColor); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockSurfaceControlHelper.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockSurfaceControlHelper.java index 49228720b81d..f8b3fb3def62 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockSurfaceControlHelper.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockSurfaceControlHelper.java @@ -34,13 +34,12 @@ public class MockSurfaceControlHelper { * given {@link SurfaceControl} when calling {@link SurfaceControl.Builder#build()}. * * @param mockSurfaceControl the first {@link SurfaceControl} to return - * @param mockSurfaceControls following {@link SurfaceControl} to return * @return the mock of {@link SurfaceControl.Builder} */ public static SurfaceControl.Builder createMockSurfaceControlBuilder( - SurfaceControl mockSurfaceControl, SurfaceControl... mockSurfaceControls) { + SurfaceControl mockSurfaceControl) { final SurfaceControl.Builder mockBuilder = mock(SurfaceControl.Builder.class, RETURNS_SELF); - doReturn(mockSurfaceControl, (Object[]) mockSurfaceControls) + doReturn(mockSurfaceControl) .when(mockBuilder) .build(); return mockBuilder; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java index 304ca66dd3bb..1d038f4ee377 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java @@ -182,7 +182,7 @@ public class SplitTransitionTests extends ShellTestCase { IBinder transition = mSplitScreenTransitions.startEnterTransition( TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(), - new RemoteTransition(testRemote), mStageCoordinator); + new RemoteTransition(testRemote), mStageCoordinator, null); mMainStage.onTaskAppeared(mMainChild, createMockSurface()); mSideStage.onTaskAppeared(mSideChild, createMockSurface()); boolean accepted = mStageCoordinator.startAnimation(transition, info, @@ -422,7 +422,7 @@ public class SplitTransitionTests extends ShellTestCase { TransitionInfo enterInfo = createEnterPairInfo(); IBinder enterTransit = mSplitScreenTransitions.startEnterTransition( TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(), - new RemoteTransition(new TestRemoteTransition()), mStageCoordinator); + new RemoteTransition(new TestRemoteTransition()), mStageCoordinator, null); mMainStage.onTaskAppeared(mMainChild, createMockSurface()); mSideStage.onTaskAppeared(mSideChild, createMockSurface()); mStageCoordinator.startAnimation(enterTransit, enterInfo, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index 680034bd2ea5..d1b837ef42f1 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -21,23 +21,32 @@ import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceCon import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.same; import static org.mockito.Mockito.verify; import android.app.ActivityManager; import android.content.Context; import android.graphics.Color; +import android.graphics.Point; import android.graphics.Rect; import android.testing.AndroidTestingRunner; +import android.util.DisplayMetrics; import android.view.Display; +import android.view.InsetsState; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.View; +import android.view.ViewRootImpl; +import android.view.WindowManager.LayoutParams; import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; @@ -53,6 +62,8 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import java.util.ArrayList; +import java.util.List; import java.util.function.Supplier; /** @@ -66,6 +77,8 @@ import java.util.function.Supplier; public class WindowDecorationTests extends ShellTestCase { private static final int CAPTION_HEIGHT_DP = 32; private static final int SHADOW_RADIUS_DP = 5; + private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400); + private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60); private final Rect mOutsetsDp = new Rect(); private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult = @@ -84,12 +97,11 @@ public class WindowDecorationTests extends ShellTestCase { @Mock private WindowContainerTransaction mMockWindowContainerTransaction; - private SurfaceControl.Builder mMockSurfaceControlBuilder; + private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>(); private SurfaceControl.Transaction mMockSurfaceControlTransaction; @Before public void setUp() { - mMockSurfaceControlBuilder = createMockSurfaceControlBuilder(mock(SurfaceControl.class)); mMockSurfaceControlTransaction = createMockSurfaceControlTransaction(); doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory) @@ -97,6 +109,128 @@ public class WindowDecorationTests extends ShellTestCase { } @Test + public void testLayoutResultCalculation_invisibleTask() { + final Display defaultDisplay = mock(Display.class); + doReturn(defaultDisplay).when(mMockDisplayController) + .getDisplay(Display.DEFAULT_DISPLAY); + + final SurfaceControl decorContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder decorContainerSurfaceBuilder = + createMockSurfaceControlBuilder(decorContainerSurface); + mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder taskBackgroundSurfaceBuilder = + createMockSurfaceControlBuilder(taskBackgroundSurface); + mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder); + + final ActivityManager.TaskDescription.Builder taskDescriptionBuilder = + new ActivityManager.TaskDescription.Builder() + .setBackgroundColor(Color.YELLOW); + final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setTaskDescriptionBuilder(taskDescriptionBuilder) + .setBounds(TASK_BOUNDS) + .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y) + .setVisible(false) + .build(); + taskInfo.isFocused = false; + // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is + // 64px. + taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; + mOutsetsDp.set(10, 20, 30, 40); + + final SurfaceControl taskSurface = mock(SurfaceControl.class); + final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); + + windowDecor.relayout(taskInfo); + + verify(decorContainerSurfaceBuilder, never()).build(); + verify(taskBackgroundSurfaceBuilder, never()).build(); + verify(mMockSurfaceControlViewHostFactory, never()) + .create(any(), any(), any(), anyBoolean()); + + verify(mMockSurfaceControlTransaction).hide(taskSurface); + + assertNull(mRelayoutResult.mRootView); + } + + @Test + public void testLayoutResultCalculation_visibleFocusedTask() { + final Display defaultDisplay = mock(Display.class); + doReturn(defaultDisplay).when(mMockDisplayController) + .getDisplay(Display.DEFAULT_DISPLAY); + + final SurfaceControl decorContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder decorContainerSurfaceBuilder = + createMockSurfaceControlBuilder(decorContainerSurface); + mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder taskBackgroundSurfaceBuilder = + createMockSurfaceControlBuilder(taskBackgroundSurface); + mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder); + + final ActivityManager.TaskDescription.Builder taskDescriptionBuilder = + new ActivityManager.TaskDescription.Builder() + .setBackgroundColor(Color.YELLOW); + final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setTaskDescriptionBuilder(taskDescriptionBuilder) + .setBounds(TASK_BOUNDS) + .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y) + .setVisible(true) + .build(); + taskInfo.isFocused = true; + // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is + // 64px. + taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; + mOutsetsDp.set(10, 20, 30, 40); + + final SurfaceControl taskSurface = mock(SurfaceControl.class); + final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); + + windowDecor.relayout(taskInfo); + + verify(decorContainerSurfaceBuilder).setParent(taskSurface); + verify(decorContainerSurfaceBuilder).setContainerLayer(); + verify(mMockSurfaceControlTransaction).setTrustedOverlay(decorContainerSurface, true); + verify(mMockSurfaceControlTransaction).setPosition(decorContainerSurface, -20, -40); + verify(mMockSurfaceControlTransaction).setWindowCrop(decorContainerSurface, 380, 220); + + verify(taskBackgroundSurfaceBuilder).setParent(taskSurface); + verify(taskBackgroundSurfaceBuilder).setEffectLayer(); + verify(mMockSurfaceControlTransaction).setWindowCrop(taskBackgroundSurface, 300, 100); + verify(mMockSurfaceControlTransaction) + .setColor(taskBackgroundSurface, new float[] {1.f, 1.f, 0.f}); + verify(mMockSurfaceControlTransaction).setShadowRadius(taskBackgroundSurface, 10); + + verify(mMockSurfaceControlViewHostFactory) + .create(any(), eq(defaultDisplay), any(), anyBoolean()); + verify(mMockSurfaceControlViewHost) + .setView(same(mMockView), + argThat(lp -> lp.height == 64 + && lp.width == 300 + && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0)); + if (ViewRootImpl.CAPTION_ON_SHELL) { + verify(mMockView).setTaskFocusState(true); + verify(mMockWindowContainerTransaction) + .addRectInsetsProvider(taskInfo.token, + new Rect(100, 300, 400, 364), + new int[] { InsetsState.ITYPE_CAPTION_BAR }); + } + + verify(mMockSurfaceControlTransaction) + .setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y); + verify(mMockSurfaceControlTransaction) + .setCrop(taskSurface, new Rect(-20, -40, 360, 180)); + verify(mMockSurfaceControlTransaction) + .show(taskSurface); + + assertEquals(380, mRelayoutResult.mWidth); + assertEquals(220, mRelayoutResult.mHeight); + assertEquals(2, mRelayoutResult.mDensity, 0.f); + } + + @Test public void testNotCrashWhenDisplayAppearsAfterTask() { doReturn(mock(Display.class)).when(mMockDisplayController) .getDisplay(Display.DEFAULT_DISPLAY); @@ -145,10 +279,24 @@ public class WindowDecorationTests extends ShellTestCase { private TestWindowDecoration createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) { return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer, - taskInfo, testSurface, () -> mMockSurfaceControlBuilder, + taskInfo, testSurface, new MockSurfaceControlBuilderSupplier(), mMockSurfaceControlViewHostFactory); } + private class MockSurfaceControlBuilderSupplier implements Supplier<SurfaceControl.Builder> { + private int mNumOfCalls = 0; + + @Override + public SurfaceControl.Builder get() { + final SurfaceControl.Builder builder = + mNumOfCalls < mMockSurfaceControlBuilders.size() + ? mMockSurfaceControlBuilders.get(mNumOfCalls) + : createMockSurfaceControlBuilder(mock(SurfaceControl.class)); + ++mNumOfCalls; + return builder; + } + } + private static class TestView extends View implements TaskFocusStateConsumer { private TestView(Context context) { super(context); diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 26244125866a..ddbe6d6a0f17 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -890,7 +890,7 @@ <!-- The maximum offset for the under-display fingerprint sensor (UDFPS) icon in either direction that elements are moved to prevent burn-in on AOD--> <dimen name="udfps_burn_in_offset_x">7px</dimen> - <dimen name="udfps_burn_in_offset_y">28px</dimen> + <dimen name="udfps_burn_in_offset_y">20px</dimen> <!-- The absolute side margins of quick settings --> <dimen name="quick_settings_bottom_margin_media">8dp</dimen> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java index e3f568732b9d..422274469dcc 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java @@ -16,6 +16,7 @@ package com.android.systemui.shared.recents.model; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; @@ -245,12 +246,16 @@ public class Task { */ public static Task from(TaskKey taskKey, TaskInfo taskInfo, boolean isLocked) { ActivityManager.TaskDescription td = taskInfo.taskDescription; + // Also consider undefined activity type to include tasks in overview right after rebooting + // the device. + final boolean isDockable = taskInfo.supportsMultiWindow + && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode()) + && (taskInfo.getActivityType() == ACTIVITY_TYPE_UNDEFINED + || ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType())); return new Task(taskKey, td != null ? td.getPrimaryColor() : 0, - td != null ? td.getBackgroundColor() : 0, taskInfo.supportsMultiWindow - && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType()) - && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode()), - isLocked, td, taskInfo.topActivity); + td != null ? td.getBackgroundColor() : 0, isDockable , isLocked, td, + taskInfo.topActivity); } public Task(TaskKey key) { diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java index c9631549cd76..4a0a07b9783c 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java +++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java @@ -38,6 +38,7 @@ import android.app.ActivityManager; import android.app.ActivityManager.ProcessCapability; import android.net.NetworkPolicyManager; import android.os.UserHandle; +import android.util.ArraySet; import android.util.Log; import android.util.Slog; @@ -79,6 +80,8 @@ public class NetworkPolicyLogger { private static final int EVENT_APP_IDLE_WL_CHANGED = 14; private static final int EVENT_METERED_ALLOWLIST_CHANGED = 15; private static final int EVENT_METERED_DENYLIST_CHANGED = 16; + private static final int EVENT_ROAMING_CHANGED = 17; + private static final int EVENT_INTERFACES_CHANGED = 18; private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE); private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE); @@ -265,6 +268,24 @@ public class NetworkPolicyLogger { } } + void roamingChanged(int netId, boolean newRoaming) { + synchronized (mLock) { + if (LOGD || mDebugUid != INVALID_UID) { + Slog.d(TAG, getRoamingChangedLog(netId, newRoaming)); + } + mEventsBuffer.roamingChanged(netId, newRoaming); + } + } + + void interfacesChanged(int netId, ArraySet<String> newIfaces) { + synchronized (mLock) { + if (LOGD || mDebugUid != INVALID_UID) { + Slog.d(TAG, getInterfacesChangedLog(netId, newIfaces.toString())); + } + mEventsBuffer.interfacesChanged(netId, newIfaces.toString()); + } + } + void setDebugUid(int uid) { mDebugUid = uid; } @@ -348,6 +369,14 @@ public class NetworkPolicyLogger { return "metered-denylist for " + uid + " changed to " + added; } + private static String getRoamingChangedLog(int netId, boolean newRoaming) { + return "Roaming of netId=" + netId + " changed to " + newRoaming; + } + + private static String getInterfacesChangedLog(int netId, String newIfaces) { + return "Interfaces of netId=" + netId + " changed to " + newIfaces; + } + private static String getFirewallChainName(int chain) { switch (chain) { case FIREWALL_CHAIN_DOZABLE: @@ -570,6 +599,28 @@ public class NetworkPolicyLogger { data.timeStamp = System.currentTimeMillis(); } + public void roamingChanged(int netId, boolean newRoaming) { + final Data data = getNextSlot(); + if (data == null) return; + + data.reset(); + data.type = EVENT_ROAMING_CHANGED; + data.ifield1 = netId; + data.bfield1 = newRoaming; + data.timeStamp = System.currentTimeMillis(); + } + + public void interfacesChanged(int netId, String newIfaces) { + final Data data = getNextSlot(); + if (data == null) return; + + data.reset(); + data.type = EVENT_INTERFACES_CHANGED; + data.ifield1 = netId; + data.sfield1 = newIfaces; + data.timeStamp = System.currentTimeMillis(); + } + public void reverseDump(IndentingPrintWriter pw) { final Data[] allData = toArray(); for (int i = allData.length - 1; i >= 0; --i) { @@ -621,6 +672,10 @@ public class NetworkPolicyLogger { return getMeteredAllowlistChangedLog(data.ifield1, data.bfield1); case EVENT_METERED_DENYLIST_CHANGED: return getMeteredDenylistChangedLog(data.ifield1, data.bfield1); + case EVENT_ROAMING_CHANGED: + return getRoamingChangedLog(data.ifield1, data.bfield1); + case EVENT_INTERFACES_CHANGED: + return getInterfacesChangedLog(data.ifield1, data.sfield1); default: return String.valueOf(data.type); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 99a488c27dbb..de83f5ae7545 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -1367,8 +1367,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean roamingChanged = updateCapabilityChange( mNetworkRoaming, newRoaming, network); - if (meteredChanged || roamingChanged) { + final boolean shouldUpdateNetworkRules = meteredChanged || roamingChanged; + + if (meteredChanged) { mLogger.meterednessChanged(network.getNetId(), newMetered); + } + + if (roamingChanged) { + mLogger.roamingChanged(network.getNetId(), newRoaming); + } + + if (shouldUpdateNetworkRules) { updateNetworkRulesNL(); } } @@ -1381,6 +1390,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean ifacesChanged = updateNetworkToIfacesNL(network.getNetId(), newIfaces); if (ifacesChanged) { + mLogger.interfacesChanged(network.getNetId(), newIfaces); updateNetworkRulesNL(); } } diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp index cdb6324988be..e44ce3c43370 100644 --- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp +++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp @@ -34,4 +34,5 @@ android_test { ], platform_apis: true, test_suites: ["device-tests"], + data: [":AppEnumerationSyncProviderTestApp"], } diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml index f48974a3b8e0..cca8ec7c374f 100644 --- a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml +++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml @@ -30,7 +30,7 @@ </target_preparer> <!-- Load additional APKs onto device --> - <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> <option name="push" value="AppEnumerationSyncProviderTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationSyncProviderTestApp.apk" /> <option name="push" value="AppEnumerationHasAppOpPermissionTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationHasAppOpPermissionTestApp.apk" /> <option name="push" value="AppEnumerationSharedUserTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationSharedUserTestApp.apk" /> |