From a1dbe9cbfa0610107df7c47a4d5388a8e484d7d7 Mon Sep 17 00:00:00 2001 From: Brad Stenning Date: Wed, 2 May 2018 08:29:28 -0700 Subject: [PATCH] Add a path to allow detection of task changes to the top of the ActivityView Bug:79141700 Test: Manual with and app that registers for the new event. Change-Id: I26aa2f6cd0ada1eb777364213c159e1e7d951a33 --- core/java/android/app/ActivityView.java | 74 ++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 7032a2fe21cf..e469098e22d5 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -24,6 +24,7 @@ import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.hardware.input.InputManager; import android.os.RemoteException; +import android.os.UserHandle; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -111,6 +112,11 @@ public class ActivityView extends ViewGroup { * @see #startActivity(Intent) */ public abstract void onActivityViewDestroyed(ActivityView view); + /** + * Called when a task is moved to the front of the stack inside the container. + * This is a filtered version of {@link TaskStackListener} + */ + public void onTaskMovedToFront(ActivityManager.StackInfo stackInfo) { } } /** @@ -155,6 +161,28 @@ public class ActivityView extends ViewGroup { /** * Launch a new activity into this container. + *

Activity resolved by the provided {@link Intent} must have + * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be + * launched here. Also, if activity is not owned by the owner of this container, it must allow + * embedding and the caller must have permission to embed. + *

Note: This class must finish initializing and + * {@link StateCallback#onActivityViewReady(ActivityView)} callback must be triggered before + * this method can be called. + * + * @param intent Intent used to launch an activity. + * @param user The UserHandle of the user to start this activity for. + * + * + * @see StateCallback + * @see #startActivity(PendingIntent) + */ + public void startActivity(@NonNull Intent intent, UserHandle user) { + final ActivityOptions options = prepareActivityOptions(); + getContext().startActivityAsUser(intent, options.toBundle(), user); + } + + /** + * Launch a new activity into this container. *

Activity resolved by the provided {@link PendingIntent} must have * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be * launched here. Also, if activity is not owned by the owner of this container, it must allow @@ -303,7 +331,9 @@ public class ActivityView extends ViewGroup { final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); mVirtualDisplay = displayManager.createVirtualDisplay( DISPLAY_NAME + "@" + System.identityHashCode(this), - width, height, getBaseDisplayDensity(), mSurface, 0 /* flags */); + width, height, getBaseDisplayDensity(), mSurface, + DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC + | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); if (mVirtualDisplay == null) { Log.e(TAG, "Failed to initialize ActivityView"); return; @@ -317,7 +347,7 @@ public class ActivityView extends ViewGroup { e.rethrowAsRuntimeException(); } mInputForwarder = InputManager.getInstance().createInputForwarder(displayId); - mTaskStackListener = new TaskBackgroundChangeListener(); + mTaskStackListener = new TaskStackListenerImpl(); try { mActivityManager.registerTaskStackListener(mTaskStackListener); } catch (RemoteException e) { @@ -403,8 +433,11 @@ public class ActivityView extends ViewGroup { * A task change listener that detects background color change of the topmost stack on our * virtual display and updates the background of the surface view. This background will be shown * when surface view is resized, but the app hasn't drawn its content in new size yet. + * It also calls StateCallback.onTaskMovedToFront to notify interested parties that the stack + * associated with the {@link ActivityView} has had a Task moved to the front. This is useful + * when needing to also bring the host Activity to the foreground at the same time. */ - private class TaskBackgroundChangeListener extends TaskStackListener { + private class TaskStackListenerImpl extends TaskStackListener { @Override public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td) @@ -413,6 +446,31 @@ public class ActivityView extends ViewGroup { return; } + StackInfo stackInfo = getTopMostStackInfo(); + if (stackInfo == null) { + return; + } + // Found the topmost stack on target display. Now check if the topmost task's + // description changed. + if (taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) { + mSurfaceView.setResizeBackgroundColor(td.getBackgroundColor()); + } + } + + @Override + public void onTaskMovedToFront(int taskId) throws RemoteException { + if (mActivityViewCallback != null) { + StackInfo stackInfo = getTopMostStackInfo(); + // if StackInfo was null or unrelated to the "move to front" then there's no use + // notifying the callback + if (stackInfo != null + && taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) { + mActivityViewCallback.onTaskMovedToFront(stackInfo); + } + } + } + + private StackInfo getTopMostStackInfo() throws RemoteException { // Find the topmost task on our virtual display - it will define the background // color of the surface view during resizing. final int displayId = mVirtualDisplay.getDisplay().getDisplayId(); @@ -426,14 +484,10 @@ public class ActivityView extends ViewGroup { if (stackInfo.displayId != displayId) { continue; } - // Found the topmost stack on target display. Now check if the topmost task's - // description changed. - if (taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) { - mSurfaceView.setResizeBackgroundColor(td.getBackgroundColor()); - } - break; + // Found the topmost stack on target display. + return stackInfo; } + return null; } } - } -- 2.11.0