Use PhoneWindow for screenshots

Bug: 174554386
Bug: 159419046
Fix: 174554386

Test: manual

Change-Id: Ie2df84d8650adf6e3d5d4b37b645122983045e92
This commit is contained in:
Miranda Kephart
2020-11-30 16:11:30 -05:00
parent 343b6ddaf5
commit 09f4e92673
4 changed files with 62 additions and 36 deletions

View File

@@ -40,18 +40,4 @@
android:visibility="gone"
android:pointerIcon="crosshair"/>
<include layout="@layout/global_screenshot_static"/>
<FrameLayout
android:id="@+id/global_screenshot_dismiss_button"
android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
android:elevation="7dp"
android:visibility="gone"
android:contentDescription="@string/screenshot_dismiss_description">
<ImageView
android:id="@+id/global_screenshot_dismiss_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/screenshot_dismiss_button_margin"
android:src="@drawable/screenshot_cancel"/>
</FrameLayout>
</com.android.systemui.screenshot.ScreenshotView>

View File

@@ -17,7 +17,6 @@
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
@@ -62,4 +61,22 @@
</LinearLayout>
</HorizontalScrollView>
<include layout="@layout/global_screenshot_preview"/>
<FrameLayout
android:id="@+id/global_screenshot_dismiss_button"
android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
android:elevation="7dp"
android:visibility="gone"
app:layout_constraintStart_toEndOf="@id/global_screenshot_preview"
app:layout_constraintEnd_toEndOf="@id/global_screenshot_preview"
app:layout_constraintTop_toTopOf="@id/global_screenshot_preview"
app:layout_constraintBottom_toTopOf="@id/global_screenshot_preview"
android:contentDescription="@string/screenshot_dismiss_description">
<ImageView
android:id="@+id/global_screenshot_dismiss_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/screenshot_dismiss_button_margin"
android:src="@drawable/screenshot_cancel"/>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -19,6 +19,8 @@ package com.android.systemui.screenshot;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static java.util.Objects.requireNonNull;
@@ -52,7 +54,8 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -60,6 +63,7 @@ import android.widget.Toast;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
import com.android.systemui.R;
import com.android.systemui.util.DeviceConfigProxy;
@@ -147,6 +151,8 @@ public class ScreenshotController {
private final MediaActionSound mCameraSound;
private final ScrollCaptureClient mScrollCaptureClient;
private final DeviceConfigProxy mConfigProxy;
private final PhoneWindow mWindow;
private final View mDecorView;
private final Binder mWindowToken;
private ScreenshotView mScreenshotView;
@@ -189,13 +195,12 @@ public class ScreenshotController {
final DisplayManager dm = requireNonNull(context.getSystemService(DisplayManager.class));
mDisplay = dm.getDisplay(DEFAULT_DISPLAY);
mContext = context.createDisplayContext(mDisplay);
mContext = context.createWindowContext(TYPE_SCREENSHOT, null);
mWindowManager = mContext.getSystemService(WindowManager.class);
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
mConfigProxy = configProxy;
reloadAssets();
Configuration config = mContext.getResources().getConfiguration();
mInDarkMode = config.isNightModeActive();
mDirectionLTR = config.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
@@ -204,9 +209,8 @@ public class ScreenshotController {
mScrollCaptureClient.setHostWindowToken(mWindowToken);
// Setup the window that we are going to use
mWindowLayoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
WindowManager.LayoutParams.TYPE_SCREENSHOT,
mWindowLayoutParams = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT, 0, 0,
TYPE_SCREENSHOT,
WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -217,11 +221,19 @@ public class ScreenshotController {
mWindowLayoutParams.setTitle("ScreenshotAnimation");
mWindowLayoutParams.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
mWindowLayoutParams.setFitInsetsTypes(0 /* types */);
mWindowLayoutParams.token = mWindowToken;
// This is needed to let touches pass through outside the touchable areas
mWindowLayoutParams.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
mWindow = new PhoneWindow(mContext);
mWindow.setWindowManager(mWindowManager, null, null);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
mWindow.setBackgroundDrawableResource(android.R.color.transparent);
mDecorView = mWindow.getDecorView();
reloadAssets();
mDisplayMetrics = new DisplayMetrics();
mDisplay.getRealMetrics(mDisplayMetrics);
@@ -355,11 +367,21 @@ public class ScreenshotController {
* button and the actions container background, since the buttons are re-inflated on demand.
*/
private void reloadAssets() {
boolean wasAttached = mScreenshotView != null && mScreenshotView.isAttachedToWindow();
boolean wasAttached = mDecorView.isAttachedToWindow();
if (wasAttached) {
mWindowManager.removeView(mScreenshotView);
mWindowManager.removeView(mDecorView);
}
// respect the display cutout in landscape (since we'd otherwise overlap) but not portrait
mWindowLayoutParams.setFitInsetsTypes(
mOrientationPortrait ? 0 : WindowInsets.Type.displayCutout());
// ignore system bar insets for the purpose of window layout
mDecorView.setOnApplyWindowInsetsListener((v, insets) -> v.onApplyWindowInsets(
new WindowInsets.Builder(insets)
.setInsets(WindowInsets.Type.all(), Insets.NONE)
.build()));
// Inflate the screenshot layout
mScreenshotView = (ScreenshotView)
LayoutInflater.from(mContext).inflate(R.layout.global_screenshot, null);
@@ -382,9 +404,8 @@ public class ScreenshotController {
return false;
});
if (wasAttached) {
mWindowManager.addView(mScreenshotView, mWindowLayoutParams);
}
// view is added to window manager in startAnimation
mWindow.setContentView(mScreenshotView, mWindowLayoutParams);
}
/**
@@ -510,10 +531,10 @@ public class ScreenshotController {
mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
mScreenshotHandler.post(() -> {
if (!mScreenshotView.isAttachedToWindow()) {
mWindowManager.addView(mScreenshotView, mWindowLayoutParams);
mWindowManager.addView(mWindow.getDecorView(), mWindowLayoutParams);
}
mScreenshotView.prepareForAnimation(mScreenBitmap, screenRect, screenInsets);
mScreenshotView.prepareForAnimation(mScreenBitmap, screenInsets);
mScreenshotHandler.post(() -> {
mScreenshotView.getViewTreeObserver().addOnComputeInternalInsetsListener(
@@ -541,7 +562,7 @@ public class ScreenshotController {
private void resetScreenshotView() {
if (mScreenshotView.isAttachedToWindow()) {
mWindowManager.removeView(mScreenshotView);
mWindowManager.removeView(mDecorView);
}
mScreenshotView.reset();
mOnCompleteRunnable.run();
@@ -636,8 +657,8 @@ public class ScreenshotController {
} else {
mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
}
if (mScreenshotView.isAttachedToWindow()) {
mWindowManager.updateViewLayout(mScreenshotView, mWindowLayoutParams);
if (mDecorView.isAttachedToWindow()) {
mWindowManager.updateViewLayout(mDecorView, mWindowLayoutParams);
}
}

View File

@@ -240,8 +240,7 @@ public class ScreenshotView extends FrameLayout implements
setOnApplyWindowInsetsListener((v, insets) -> {
if (QuickStepContract.isGesturalMode(mNavMode)) {
Insets gestureInsets = insets.getInsets(
WindowInsets.Type.systemGestures());
Insets gestureInsets = insets.getInsets(WindowInsets.Type.systemGestures());
mLeftInset = gestureInsets.left;
mRightInset = gestureInsets.right;
} else {
@@ -272,7 +271,7 @@ public class ScreenshotView extends FrameLayout implements
mScreenshotSelectorView.requestFocus();
}
void prepareForAnimation(Bitmap bitmap, Rect screenRect, Insets screenInsets) {
void prepareForAnimation(Bitmap bitmap, Insets screenInsets) {
mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets));
// make static preview invisible (from gone) so we can query its location on screen
mScreenshotPreview.setVisibility(View.INVISIBLE);
@@ -284,6 +283,8 @@ public class ScreenshotView extends FrameLayout implements
Rect previewBounds = new Rect();
mScreenshotPreview.getBoundsOnScreen(previewBounds);
int[] previewLocation = new int[2];
mScreenshotPreview.getLocationInWindow(previewLocation);
float cornerScale =
mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height());
@@ -310,7 +311,8 @@ public class ScreenshotView extends FrameLayout implements
// animate from the current location, to the static preview location
final PointF startPos = new PointF(bounds.centerX(), bounds.centerY());
final PointF finalPos = new PointF(previewBounds.centerX(), previewBounds.centerY());
final PointF finalPos = new PointF(previewLocation[0] + previewBounds.width() / 2f,
previewLocation[1] + previewBounds.height() / 2f);
ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);