diff --git a/libs/WindowManager/Shell/res/layout/bubble_overflow_activity.xml b/libs/WindowManager/Shell/res/layout/bubble_overflow_container.xml similarity index 93% rename from libs/WindowManager/Shell/res/layout/bubble_overflow_activity.xml rename to libs/WindowManager/Shell/res/layout/bubble_overflow_container.xml index 306061911f8dc..8224d95fd9adf 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_overflow_activity.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_overflow_container.xml @@ -14,7 +14,7 @@ ~ limitations under the License --> - - + diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index cb6b54321b5e3..67f4cd25c487e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -24,7 +24,6 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.wm.shell.bubbles.BubbleOverflowActivity.EXTRA_BUBBLE_CONTROLLER; import android.annotation.NonNull; import android.annotation.SuppressLint; @@ -37,14 +36,16 @@ import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Outline; +import android.graphics.Picture; import android.graphics.Rect; import android.graphics.drawable.ShapeDrawable; -import android.os.Bundle; import android.os.RemoteException; import android.util.AttributeSet; import android.util.Log; +import android.view.LayoutInflater; import android.view.SurfaceControl; import android.view.View; import android.view.ViewGroup; @@ -77,6 +78,7 @@ public class BubbleExpandedView extends LinearLayout { private AlphaOptimizedButton mSettingsIcon; private TaskView mTaskView; + private BubbleOverflowContainerView mOverflowView; private int mTaskId = INVALID_TASK_ID; @@ -125,6 +127,7 @@ public class BubbleExpandedView extends LinearLayout { if (mDestroyed || mInitialized) { return; } + // Custom options so there is no activity transition animation ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(), 0 /* enterResId */, 0 /* exitResId */); @@ -307,15 +310,25 @@ public class BubbleExpandedView extends LinearLayout { * Initialize {@link BubbleController} and {@link BubbleStackView} here, this method must need * to be called after view inflate. */ - void initialize(BubbleController controller, BubbleStackView stackView) { + void initialize(BubbleController controller, BubbleStackView stackView, boolean isOverflow) { mController = controller; mStackView = stackView; - - mTaskView = new TaskView(mContext, mController.getTaskOrganizer()); - mExpandedViewContainer.addView(mTaskView); - bringChildToFront(mTaskView); - mTaskView.setListener(mContext.getMainExecutor(), mTaskViewListener); + mIsOverflow = isOverflow; mPositioner = mController.getPositioner(); + + if (mIsOverflow) { + mOverflowView = (BubbleOverflowContainerView) LayoutInflater.from(getContext()).inflate( + R.layout.bubble_overflow_container, null /* root */); + mOverflowView.setBubbleController(mController); + mExpandedViewContainer.addView(mOverflowView); + bringChildToFront(mOverflowView); + mSettingsIcon.setVisibility(GONE); + } else { + mTaskView = new TaskView(mContext, mController.getTaskOrganizer()); + mTaskView.setListener(mContext.getMainExecutor(), mTaskViewListener); + mExpandedViewContainer.addView(mTaskView); + bringChildToFront(mTaskView); + } } void updateDimensions() { @@ -390,6 +403,17 @@ public class BubbleExpandedView extends LinearLayout { /** Return a GraphicBuffer with the contents of the task view surface. */ @Nullable SurfaceControl.ScreenshotHardwareBuffer snapshotActivitySurface() { + if (mIsOverflow) { + // For now, just snapshot the view and return it as a hw buffer so that the animation + // code for both the tasks and overflow can be the same + Picture p = new Picture(); + mOverflowView.draw( + p.beginRecording(mOverflowView.getWidth(), mOverflowView.getHeight())); + p.endRecording(); + Bitmap snapshot = Bitmap.createBitmap(p); + return new SurfaceControl.ScreenshotHardwareBuffer(snapshot.getHardwareBuffer(), + snapshot.getColorSpace(), false /* containsSecureLayers */); + } if (mTaskView == null || mTaskView.getSurfaceControl() == null) { return null; } @@ -400,6 +424,11 @@ public class BubbleExpandedView extends LinearLayout { } int[] getTaskViewLocationOnScreen() { + if (mIsOverflow) { + // This is only used for animating away the surface when switching bubbles, just use the + // view location on screen for now to allow us to use the same animation code with tasks + return mOverflowView.getLocationOnScreen(); + } if (mTaskView != null) { return mTaskView.getLocationOnScreen(); } else { @@ -450,10 +479,7 @@ public class BubbleExpandedView extends LinearLayout { final float alpha = visibility ? 1f : 0f; mPointerView.setAlpha(alpha); - if (mTaskView == null) { - return; - } - if (alpha != mTaskView.getAlpha()) { + if (mTaskView != null) { mTaskView.setAlpha(alpha); } } @@ -467,19 +493,6 @@ public class BubbleExpandedView extends LinearLayout { return mTaskId; } - public void setOverflow(boolean overflow) { - mIsOverflow = overflow; - - Intent target = new Intent(mContext, BubbleOverflowActivity.class); - target.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK); - Bundle extras = new Bundle(); - extras.putBinder(EXTRA_BUBBLE_CONTROLLER, ObjectWrapper.wrap(mController)); - target.putExtras(extras); - mPendingIntent = PendingIntent.getActivity(mContext, 0 /* requestCode */, - target, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - mSettingsIcon.setVisibility(GONE); - } - /** * Sets the bubble used to populate this view. */ @@ -511,7 +524,8 @@ public class BubbleExpandedView extends LinearLayout { if (isNew) { mPendingIntent = mBubble.getBubbleIntent(); - if (mPendingIntent != null || mBubble.hasMetadataShortcutId()) { + if ((mPendingIntent != null || mBubble.hasMetadataShortcutId()) + && mTaskView != null) { setContentVisibility(false); mTaskView.setVisibility(VISIBLE); } @@ -552,13 +566,19 @@ public class BubbleExpandedView extends LinearLayout { desiredHeight = Math.max(desiredHeight, mMinHeight); float height = Math.min(desiredHeight, getMaxExpandedHeight()); height = Math.max(height, mMinHeight); - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mTaskView.getLayoutParams(); + FrameLayout.LayoutParams lp = mIsOverflow + ? (FrameLayout.LayoutParams) mOverflowView.getLayoutParams() + : (FrameLayout.LayoutParams) mTaskView.getLayoutParams(); mNeedsNewHeight = lp.height != height; if (!mImeVisible) { // If the ime is visible... don't adjust the height because that will cause // a configuration change and the ime will be lost. lp.height = (int) height; - mTaskView.setLayoutParams(lp); + if (mIsOverflow) { + mOverflowView.setLayoutParams(lp); + } else { + mTaskView.setLayoutParams(lp); + } mNeedsNewHeight = false; } if (DEBUG_BUBBLE_EXPANDED_VIEW) { @@ -602,6 +622,9 @@ public class BubbleExpandedView extends LinearLayout { updateHeight(); mTaskView.onLocationChanged(); } + if (mIsOverflow) { + mOverflowView.show(); + } } /** @@ -637,8 +660,8 @@ public class BubbleExpandedView extends LinearLayout { /** * Cleans up anything related to the task and TaskView. If this view should be reused after this - * method is called, then {@link #initialize(BubbleController, BubbleStackView)} must be invoked - * first. + * method is called, then {@link #initialize(BubbleController, BubbleStackView, boolean)} must + * be invoked first. */ public void cleanUpExpandedState() { if (DEBUG_BUBBLE_EXPANDED_VIEW) { @@ -653,8 +676,6 @@ public class BubbleExpandedView extends LinearLayout { } if (mTaskView != null) { mTaskView.release(); - } - if (mTaskView != null) { removeView(mTaskView); mTaskView = null; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt index 8ab2f6325d2ba..c7219089bffe3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt @@ -65,8 +65,7 @@ class BubbleOverflow( /** Call before use and again if cleanUpExpandedState was called. */ fun initialize(controller: BubbleController) { - getExpandedView()?.initialize(controller, controller.stackView) - getExpandedView()?.setOverflow(true) + getExpandedView()?.initialize(controller, controller.stackView, true /* isOverflow */) } fun cleanUpExpandedState() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java similarity index 87% rename from libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java index cfd0066e0fc3b..39e4e1a090197 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java @@ -29,16 +29,21 @@ import android.content.res.TypedArray; import android.graphics.Color; import android.os.Bundle; import android.os.IBinder; +import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -50,10 +55,9 @@ import java.util.List; import java.util.function.Consumer; /** - * Activity for showing aged out bubbles. - * Must be public to be accessible to androidx...AppComponentFactory + * Container view for showing aged out bubbles. */ -public class BubbleOverflowActivity extends Activity { +public class BubbleOverflowContainerView extends LinearLayout { static final String EXTRA_BUBBLE_CONTROLLER = "bubble_controller"; private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleOverflowActivity" : TAG_BUBBLES; @@ -95,37 +99,55 @@ public class BubbleOverflowActivity extends Activity { } } + public BubbleOverflowContainerView(Context context) { + super(context); + } + + public BubbleOverflowContainerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public BubbleOverflowContainerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public BubbleOverflowContainerView(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public void setBubbleController(BubbleController controller) { + mController = controller; + } + + public void show() { + setVisibility(View.VISIBLE); + updateOverflow(); + } + + public void hide() { + setVisibility(View.INVISIBLE); + } + @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.bubble_overflow_activity); + protected void onFinishInflate() { + super.onFinishInflate(); mRecyclerView = findViewById(R.id.bubble_overflow_recycler); mEmptyState = findViewById(R.id.bubble_overflow_empty_state); mEmptyStateTitle = findViewById(R.id.bubble_overflow_empty_title); mEmptyStateSubtitle = findViewById(R.id.bubble_overflow_empty_subtitle); mEmptyStateImage = findViewById(R.id.bubble_overflow_empty_state_image); - - Intent intent = getIntent(); - if (intent != null && intent.getExtras() != null) { - IBinder binder = intent.getExtras().getBinder(EXTRA_BUBBLE_CONTROLLER); - if (binder instanceof ObjectWrapper) { - mController = ((ObjectWrapper) binder).get(); - updateOverflow(); - } - } else { - Log.w(TAG, "Bubble overflow activity created without bubble controller!"); - } } void updateOverflow() { Resources res = getResources(); final int columns = res.getInteger(R.integer.bubbles_overflow_columns); mRecyclerView.setLayoutManager( - new NoScrollGridLayoutManager(getApplicationContext(), columns)); + new NoScrollGridLayoutManager(getContext(), columns)); DisplayMetrics displayMetrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + getContext().getDisplay().getMetrics(displayMetrics); final int overflowPadding = res.getDimensionPixelSize(R.dimen.bubble_overflow_padding); final int recyclerViewWidth = displayMetrics.widthPixels - (overflowPadding * 2); @@ -137,7 +159,7 @@ public class BubbleOverflowActivity extends Activity { - res.getDimensionPixelSize(R.dimen.bubble_overflow_padding); final int viewHeight = recyclerViewHeight / rows; - mAdapter = new BubbleOverflowAdapter(getApplicationContext(), mOverflowBubbles, + mAdapter = new BubbleOverflowAdapter(getContext(), mOverflowBubbles, mController::promoteBubbleFromOverflow, mController.getPositioner(), viewWidth, viewHeight); @@ -146,6 +168,11 @@ public class BubbleOverflowActivity extends Activity { mOverflowBubbles.clear(); mOverflowBubbles.addAll(mController.getOverflowBubbles()); mAdapter.notifyDataSetChanged(); + + // Currently BubbleExpandedView.mExpandedViewContainer is WRAP_CONTENT so use the same + // width we would use for the recycler view + LayoutParams lp = (LayoutParams) mEmptyState.getLayoutParams(); + lp.width = recyclerViewWidth; updateEmptyStateVisibility(); mController.setOverflowListener(mDataListener); @@ -172,12 +199,12 @@ public class BubbleOverflowActivity extends Activity { ? res.getDrawable(R.drawable.bubble_ic_empty_overflow_dark) : res.getDrawable(R.drawable.bubble_ic_empty_overflow_light)); - findViewById(android.R.id.content) + findViewById(R.id.bubble_overflow_container) .setBackgroundColor(isNightMode ? res.getColor(R.color.bubbles_dark) : res.getColor(R.color.bubbles_light)); - final TypedArray typedArray = getApplicationContext().obtainStyledAttributes( + final TypedArray typedArray = getContext().obtainStyledAttributes( new int[]{android.R.attr.colorBackgroundFloating, android.R.attr.textColorSecondary}); int bgColor = typedArray.getColor(0, isNightMode ? Color.BLACK : Color.WHITE); @@ -222,36 +249,6 @@ public class BubbleOverflowActivity extends Activity { } } }; - - @Override - public void onStart() { - super.onStart(); - } - - @Override - public void onRestart() { - super.onRestart(); - } - - @Override - public void onResume() { - super.onResume(); - updateOverflow(); - } - - @Override - public void onPause() { - super.onPause(); - } - - @Override - public void onStop() { - super.onStop(); - } - - public void onDestroy() { - super.onDestroy(); - } } class BubbleOverflowAdapter extends RecyclerView.Adapter { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java index e21ba6392e95b..0e7e92d9554ad 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java @@ -138,7 +138,7 @@ public class BubbleViewInfoTask extends AsyncTask - - - - -