Fork GlobalScreenshot into notif vs corner flows

Moves GlobalScreenshot into two different files: GlobalScreenshot
(with the new corner flow) and GlobalScreenshotLegacy (with the
previous notifications flow). This is to allow easier iteration on
the new flow; once it is fully tested, the notification/legacy
version will eventually be removed.

Bug: 137153302
Bug: 147423001
Test: tested old and new flows to ensure no user-visible changes; also
tested smart screenshots in old flow to ensure no behavior change
Change-Id: Ia776e2a7c2e8d0d298ea3e0f18f3419aa2b64415
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 6ac9da4..995cb7d 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
diff --git a/packages/SystemUI/res/layout/global_screenshot_legacy.xml b/packages/SystemUI/res/layout/global_screenshot_legacy.xml
new file mode 100644
index 0000000..791c7ea
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_screenshot_legacy.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <ImageView android:id="@+id/global_screenshot_legacy_background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:src="@android:color/black"
+        android:visibility="gone" />
+    <ImageView android:id="@+id/global_screenshot_legacy"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:background="@drawable/screenshot_panel"
+        android:visibility="gone"
+        android:adjustViewBounds="true" />
+    <ImageView android:id="@+id/global_screenshot_legacy_flash"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:src="@android:color/white"
+        android:visibility="gone" />
+    <com.android.systemui.screenshot.ScreenshotSelectorView
+        android:id="@+id/global_screenshot_legacy_selector"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone"
+        android:pointerIcon="crosshair"/>
+</FrameLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index da0323a..5a1151e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -288,6 +288,7 @@
     <!-- Dimensions related to screenshots -->
 
     <!-- The padding on the global screenshot background image -->
+    <dimen name="global_screenshot_legacy_bg_padding">20dp</dimen>
     <dimen name="global_screenshot_bg_padding">20dp</dimen>
     <dimen name="screenshot_action_container_corner_radius">10dp</dimen>
     <dimen name="screenshot_action_container_padding">20dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 02c4beb..91d5457 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -16,11 +16,9 @@
 
 package com.android.systemui.screenshot;
 
-import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
 import static android.view.View.VISIBLE;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_CORNER_FLOW;
 import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT;
 
 import android.animation.Animator;
@@ -50,7 +48,6 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.UserHandle;
-import android.provider.DeviceConfig;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
@@ -246,20 +243,13 @@
             mSaveInBgTask.cancel(false);
         }
 
-        if (!DeviceConfig.getBoolean(
-                NAMESPACE_SYSTEMUI, SCREENSHOT_CORNER_FLOW, false)) {
-            mNotificationsController.reset();
-            mNotificationsController.setImage(mScreenBitmap);
-            mNotificationsController.showSavingScreenshotNotification();
-        }
         mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data).execute();
     }
 
     /**
      * Takes a screenshot of the current display and shows an animation.
      */
-    private void takeScreenshot(Consumer<Uri> finisher, boolean statusBarVisible,
-            boolean navBarVisible, Rect crop) {
+    private void takeScreenshot(Consumer<Uri> finisher, Rect crop) {
         int rot = mDisplay.getRotation();
         int width = crop.width();
         int height = crop.height();
@@ -278,21 +268,20 @@
         mScreenBitmap.prepareToDraw();
 
         // Start the post-screenshot animation
-        startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
-                statusBarVisible, navBarVisible);
+        startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels);
     }
 
-    void takeScreenshot(Consumer<Uri> finisher, boolean statusBarVisible, boolean navBarVisible) {
+    void takeScreenshot(Consumer<Uri> finisher) {
         mDisplay.getRealMetrics(mDisplayMetrics);
-        takeScreenshot(finisher, statusBarVisible, navBarVisible,
+        takeScreenshot(
+                finisher,
                 new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
     }
 
     /**
      * Displays a screenshot selector
      */
-    void takeScreenshotPartial(final Consumer<Uri> finisher, final boolean statusBarVisible,
-            final boolean navBarVisible) {
+    void takeScreenshotPartial(final Consumer<Uri> finisher) {
         mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
         mScreenshotSelectorView.setOnTouchListener(new View.OnTouchListener() {
             @Override
@@ -312,8 +301,7 @@
                         if (rect != null) {
                             if (rect.width() != 0 && rect.height() != 0) {
                                 // Need mScreenshotLayout to handle it after the view disappears
-                                mScreenshotLayout.post(() -> takeScreenshot(
-                                        finisher, statusBarVisible, navBarVisible, rect));
+                                mScreenshotLayout.post(() -> takeScreenshot(finisher, rect));
                             }
                         }
 
@@ -364,8 +352,7 @@
     /**
      * Starts the animation after taking the screenshot
      */
-    private void startAnimation(final Consumer<Uri> finisher, int w, int h,
-            boolean statusBarVisible, boolean navBarVisible) {
+    private void startAnimation(final Consumer<Uri> finisher, int w, int h) {
         // If power save is on, show a toast so there is some visual indication that a screenshot
         // has been taken.
         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -385,50 +372,30 @@
             mScreenshotAnimation.removeAllListeners();
         }
 
-        boolean useCornerFlow =
-                DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SCREENSHOT_CORNER_FLOW, false);
         mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
         ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
-        ValueAnimator screenshotFadeOutAnim = useCornerFlow
-                ? createScreenshotToCornerAnimation(w, h)
-                : createScreenshotDropOutAnimation(w, h, statusBarVisible, navBarVisible);
+        ValueAnimator screenshotFadeOutAnim = createScreenshotToCornerAnimation(w, h);
         mScreenshotAnimation = new AnimatorSet();
         mScreenshotAnimation.playSequentially(screenshotDropInAnim, screenshotFadeOutAnim);
         mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 // Save the screenshot once we have a bit of time now
-                if (!useCornerFlow) {
-                    saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() {
-                        @Override
-                        void onActionsReady(Uri uri, List<Notification.Action> actions) {
-                            if (uri == null) {
-                                mNotificationsController.notifyScreenshotError(
-                                        R.string.screenshot_failed_to_capture_text);
-                            } else {
-                                mNotificationsController
-                                        .showScreenshotActionsNotification(uri, actions);
-                            }
+                saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() {
+                    @Override
+                    void onActionsReady(Uri uri, List<Notification.Action> actions) {
+                        if (uri == null) {
+                            mNotificationsController.notifyScreenshotError(
+                                    R.string.screenshot_failed_to_capture_text);
+                        } else {
+                            mScreenshotHandler.post(() ->
+                                    createScreenshotActionsShadeAnimation(actions).start());
                         }
-                    });
-                    clearScreenshot();
-                } else {
-                    saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() {
-                        @Override
-                        void onActionsReady(Uri uri, List<Notification.Action> actions) {
-                            if (uri == null) {
-                                mNotificationsController.notifyScreenshotError(
-                                        R.string.screenshot_failed_to_capture_text);
-                            } else {
-                                mScreenshotHandler.post(() ->
-                                        createScreenshotActionsShadeAnimation(actions).start());
-                            }
-                        }
-                    });
-                    mScreenshotHandler.sendMessageDelayed(
-                            mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
-                            SCREENSHOT_CORNER_TIMEOUT_MILLIS);
-                }
+                    }
+                });
+                mScreenshotHandler.sendMessageDelayed(
+                        mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
+                        SCREENSHOT_CORNER_TIMEOUT_MILLIS);
             }
         });
         mScreenshotHandler.post(() -> {
@@ -492,7 +459,7 @@
             }
 
             @Override
-            public void onAnimationEnd(android.animation.Animator animation) {
+            public void onAnimationEnd(Animator animation) {
                 mScreenshotFlash.setVisibility(View.GONE);
             }
         });
@@ -513,81 +480,6 @@
         return anim;
     }
 
-    private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible,
-            boolean navBarVisible) {
-        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
-        anim.setStartDelay(SCREENSHOT_DROP_OUT_DELAY);
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mBackgroundView.setVisibility(View.GONE);
-                mScreenshotView.setVisibility(View.GONE);
-                mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
-            }
-        });
-
-        if (!statusBarVisible || !navBarVisible) {
-            // There is no status bar/nav bar, so just fade the screenshot away in place
-            anim.setDuration(SCREENSHOT_FAST_DROP_OUT_DURATION);
-            anim.addUpdateListener(new AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    float t = (Float) animation.getAnimatedValue();
-                    float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
-                            - t * (SCREENSHOT_DROP_IN_MIN_SCALE
-                            - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
-                    mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
-                    mScreenshotView.setAlpha(1f - t);
-                    mScreenshotView.setScaleX(scaleT);
-                    mScreenshotView.setScaleY(scaleT);
-                }
-            });
-        } else {
-            // In the case where there is a status bar, animate to the origin of the bar (top-left)
-            final float scaleDurationPct = (float) SCREENSHOT_DROP_OUT_SCALE_DURATION
-                    / SCREENSHOT_DROP_OUT_DURATION;
-            final Interpolator scaleInterpolator = new Interpolator() {
-                @Override
-                public float getInterpolation(float x) {
-                    if (x < scaleDurationPct) {
-                        // Decelerate, and scale the input accordingly
-                        return (float) (1f - Math.pow(1f - (x / scaleDurationPct), 2f));
-                    }
-                    return 1f;
-                }
-            };
-
-            // Determine the bounds of how to scale
-            float halfScreenWidth = (w - 2f * mBgPadding) / 2f;
-            float halfScreenHeight = (h - 2f * mBgPadding) / 2f;
-            final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET;
-            final PointF finalPos = new PointF(
-                    -halfScreenWidth
-                            + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,
-                    -halfScreenHeight
-                            + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);
-
-            // Animate the screenshot to the status bar
-            anim.setDuration(SCREENSHOT_DROP_OUT_DURATION);
-            anim.addUpdateListener(new AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    float t = (Float) animation.getAnimatedValue();
-                    float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
-                            - scaleInterpolator.getInterpolation(t)
-                            * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE);
-                    mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
-                    mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t));
-                    mScreenshotView.setScaleX(scaleT);
-                    mScreenshotView.setScaleY(scaleT);
-                    mScreenshotView.setTranslationX(t * finalPos.x);
-                    mScreenshotView.setTranslationY(t * finalPos.y);
-                }
-            });
-        }
-        return anim;
-    }
-
     private ValueAnimator createScreenshotToCornerAnimation(int w, int h) {
         ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
         anim.setStartDelay(SCREENSHOT_DROP_OUT_DELAY);
@@ -776,8 +668,7 @@
             String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE);
             Slog.d(TAG, "Executing smart action [" + actionType + "]:" + actionIntent);
             ActivityOptions opts = ActivityOptions.makeBasic();
-            context.startActivityAsUser(actionIntent, opts.toBundle(),
-                    UserHandle.CURRENT);
+            context.startActivityAsUser(actionIntent, opts.toBundle(), UserHandle.CURRENT);
 
             ScreenshotSmartActions.notifyScreenshotAction(
                     context, intent.getStringExtra(EXTRA_ID), actionType, true);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
new file mode 100644
index 0000000..11aa80b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.Nullable;
+import android.app.Notification;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.media.MediaActionSound;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.PowerManager;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Class for handling device screen shots
+ *
+ * @deprecated will be removed when corner flow is complete and tested
+ */
+@Singleton
+@Deprecated
+public class GlobalScreenshotLegacy {
+
+    // These strings are used for communicating the action invoked to
+    // ScreenshotNotificationSmartActionsProvider.
+    static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type";
+    static final String EXTRA_ID = "android:screenshot_id";
+    static final String ACTION_TYPE_DELETE = "Delete";
+    static final String ACTION_TYPE_SHARE = "Share";
+    static final String ACTION_TYPE_EDIT = "Edit";
+    static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
+    static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
+
+    static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
+    static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
+    static final String EXTRA_DISALLOW_ENTER_PIP = "android:screenshot_disallow_enter_pip";
+
+    private static final String TAG = "GlobalScreenshot";
+
+    private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
+    private static final int SCREENSHOT_DROP_IN_DURATION = 430;
+    private static final int SCREENSHOT_DROP_OUT_DELAY = 500;
+    private static final int SCREENSHOT_DROP_OUT_DURATION = 430;
+    private static final int SCREENSHOT_DROP_OUT_SCALE_DURATION = 370;
+    private static final int SCREENSHOT_FAST_DROP_OUT_DURATION = 320;
+    private static final float BACKGROUND_ALPHA = 0.5f;
+    private static final float SCREENSHOT_SCALE = 1f;
+    private static final float SCREENSHOT_DROP_IN_MIN_SCALE = SCREENSHOT_SCALE * 0.725f;
+    private static final float SCREENSHOT_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.45f;
+    private static final float SCREENSHOT_FAST_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.6f;
+    private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f;
+
+    private final ScreenshotNotificationsController mNotificationsController;
+
+    private Context mContext;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mWindowLayoutParams;
+    private Display mDisplay;
+    private DisplayMetrics mDisplayMetrics;
+
+    private Bitmap mScreenBitmap;
+    private View mScreenshotLayout;
+    private ScreenshotSelectorView mScreenshotSelectorView;
+    private ImageView mBackgroundView;
+    private ImageView mScreenshotView;
+    private ImageView mScreenshotFlash;
+
+    private AnimatorSet mScreenshotAnimation;
+
+    private float mBgPadding;
+    private float mBgPaddingScale;
+
+    private AsyncTask<Void, Void, Void> mSaveInBgTask;
+
+    private MediaActionSound mCameraSound;
+
+    /**
+     * @param context everything needs a context :(
+     */
+    @Inject
+    public GlobalScreenshotLegacy(
+            Context context, @Main Resources resources, LayoutInflater layoutInflater,
+            ScreenshotNotificationsController screenshotNotificationsController) {
+        mContext = context;
+        mNotificationsController = screenshotNotificationsController;
+
+        // Inflate the screenshot layout
+        mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot_legacy, null);
+        mBackgroundView = mScreenshotLayout.findViewById(R.id.global_screenshot_legacy_background);
+        mScreenshotView = mScreenshotLayout.findViewById(R.id.global_screenshot_legacy);
+
+        mScreenshotFlash = mScreenshotLayout.findViewById(R.id.global_screenshot_legacy_flash);
+        mScreenshotSelectorView = mScreenshotLayout.findViewById(
+                R.id.global_screenshot_legacy_selector);
+        mScreenshotLayout.setFocusable(true);
+        mScreenshotSelectorView.setFocusable(true);
+        mScreenshotSelectorView.setFocusableInTouchMode(true);
+        mScreenshotLayout.setOnTouchListener((v, event) -> {
+            // Intercept and ignore all touch events
+            return true;
+        });
+
+        // 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,
+                WindowManager.LayoutParams.FLAG_FULLSCREEN
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
+                PixelFormat.TRANSLUCENT);
+        mWindowLayoutParams.setTitle("ScreenshotAnimation");
+        mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        mWindowLayoutParams.setFitWindowInsetsTypes(0 /* types */);
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        mDisplay = mWindowManager.getDefaultDisplay();
+        mDisplayMetrics = new DisplayMetrics();
+        mDisplay.getRealMetrics(mDisplayMetrics);
+
+        // Scale has to account for both sides of the bg
+        mBgPadding = (float) resources.getDimensionPixelSize(
+                R.dimen.global_screenshot_legacy_bg_padding);
+        mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;
+
+
+        // Setup the Camera shutter sound
+        mCameraSound = new MediaActionSound();
+        mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
+    }
+
+    /**
+     * Creates a new worker thread and saves the screenshot to the media store.
+     */
+    private void saveScreenshotInWorkerThread(
+            Consumer<Uri> finisher,
+            @Nullable GlobalScreenshot.ActionsReadyListener actionsReadyListener) {
+        GlobalScreenshot.SaveImageInBackgroundData data =
+                new GlobalScreenshot.SaveImageInBackgroundData();
+        data.image = mScreenBitmap;
+        data.finisher = finisher;
+        data.mActionsReadyListener = actionsReadyListener;
+        if (mSaveInBgTask != null) {
+            mSaveInBgTask.cancel(false);
+        }
+
+        mNotificationsController.reset();
+        mNotificationsController.setImage(mScreenBitmap);
+        mNotificationsController.showSavingScreenshotNotification();
+
+        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data).execute();
+    }
+
+    /**
+     * Takes a screenshot of the current display and shows an animation.
+     */
+    private void takeScreenshot(Consumer<Uri> finisher, boolean statusBarVisible,
+            boolean navBarVisible, Rect crop) {
+        int rot = mDisplay.getRotation();
+        int width = crop.width();
+        int height = crop.height();
+
+        // Take the screenshot
+        mScreenBitmap = SurfaceControl.screenshot(crop, width, height, rot);
+        if (mScreenBitmap == null) {
+            mNotificationsController.notifyScreenshotError(
+                    R.string.screenshot_failed_to_capture_text);
+            finisher.accept(null);
+            return;
+        }
+
+        // Optimizations
+        mScreenBitmap.setHasAlpha(false);
+        mScreenBitmap.prepareToDraw();
+
+        // Start the post-screenshot animation
+        startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
+                statusBarVisible, navBarVisible);
+    }
+
+    void takeScreenshot(Consumer<Uri> finisher, boolean statusBarVisible, boolean navBarVisible) {
+        mDisplay.getRealMetrics(mDisplayMetrics);
+        takeScreenshot(finisher, statusBarVisible, navBarVisible,
+                new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
+    }
+
+    /**
+     * Displays a screenshot selector
+     */
+    void takeScreenshotPartial(final Consumer<Uri> finisher, final boolean statusBarVisible,
+            final boolean navBarVisible) {
+        mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+        mScreenshotSelectorView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                ScreenshotSelectorView view = (ScreenshotSelectorView) v;
+                switch (event.getAction()) {
+                    case MotionEvent.ACTION_DOWN:
+                        view.startSelection((int) event.getX(), (int) event.getY());
+                        return true;
+                    case MotionEvent.ACTION_MOVE:
+                        view.updateSelection((int) event.getX(), (int) event.getY());
+                        return true;
+                    case MotionEvent.ACTION_UP:
+                        view.setVisibility(View.GONE);
+                        mWindowManager.removeView(mScreenshotLayout);
+                        final Rect rect = view.getSelectionRect();
+                        if (rect != null) {
+                            if (rect.width() != 0 && rect.height() != 0) {
+                                // Need mScreenshotLayout to handle it after the view disappears
+                                mScreenshotLayout.post(() -> takeScreenshot(
+                                        finisher, statusBarVisible, navBarVisible, rect));
+                            }
+                        }
+
+                        view.stopSelection();
+                        return true;
+                }
+
+                return false;
+            }
+        });
+        mScreenshotLayout.post(new Runnable() {
+            @Override
+            public void run() {
+                mScreenshotSelectorView.setVisibility(View.VISIBLE);
+                mScreenshotSelectorView.requestFocus();
+            }
+        });
+    }
+
+    /**
+     * Cancels screenshot request
+     */
+    void stopScreenshot() {
+        // If the selector layer still presents on screen, we remove it and resets its state.
+        if (mScreenshotSelectorView.getSelectionRect() != null) {
+            mWindowManager.removeView(mScreenshotLayout);
+            mScreenshotSelectorView.stopSelection();
+        }
+    }
+
+    /**
+     * Clears current screenshot
+     */
+    private void clearScreenshot() {
+        if (mScreenshotLayout.isAttachedToWindow()) {
+            mWindowManager.removeView(mScreenshotLayout);
+        }
+
+        // Clear any references to the bitmap
+        mScreenBitmap = null;
+        mScreenshotView.setImageBitmap(null);
+        mBackgroundView.setVisibility(View.GONE);
+        mScreenshotView.setVisibility(View.GONE);
+        mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
+    }
+
+    /**
+     * Starts the animation after taking the screenshot
+     */
+    private void startAnimation(final Consumer<Uri> finisher, int w, int h,
+            boolean statusBarVisible, boolean navBarVisible) {
+        // If power save is on, show a toast so there is some visual indication that a screenshot
+        // has been taken.
+        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        if (powerManager.isPowerSaveMode()) {
+            Toast.makeText(mContext, R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show();
+        }
+
+        // Add the view for the animation
+        mScreenshotView.setImageBitmap(mScreenBitmap);
+        mScreenshotLayout.requestFocus();
+
+        // Setup the animation with the screenshot just taken
+        if (mScreenshotAnimation != null) {
+            if (mScreenshotAnimation.isStarted()) {
+                mScreenshotAnimation.end();
+            }
+            mScreenshotAnimation.removeAllListeners();
+        }
+
+        mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+        ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
+        ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,
+                statusBarVisible, navBarVisible);
+        mScreenshotAnimation = new AnimatorSet();
+        mScreenshotAnimation.playSequentially(screenshotDropInAnim, screenshotFadeOutAnim);
+        mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Save the screenshot once we have a bit of time now
+                saveScreenshotInWorkerThread(finisher, new GlobalScreenshot.ActionsReadyListener() {
+                    @Override
+                    void onActionsReady(Uri uri, List<Notification.Action> actions) {
+                        if (uri == null) {
+                            mNotificationsController.notifyScreenshotError(
+                                    R.string.screenshot_failed_to_capture_text);
+                        } else {
+                            mNotificationsController.showScreenshotActionsNotification(
+                                    uri, actions);
+                        }
+                    }
+                });
+                clearScreenshot();
+            }
+        });
+        mScreenshotLayout.post(() -> {
+            // Play the shutter sound to notify that we've taken a screenshot
+            mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
+
+            mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            mScreenshotView.buildLayer();
+            mScreenshotAnimation.start();
+        });
+    }
+
+    private ValueAnimator createScreenshotDropInAnimation() {
+        final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)
+                / SCREENSHOT_DROP_IN_DURATION);
+        final float flashDurationPct = 2f * flashPeakDurationPct;
+        final Interpolator flashAlphaInterpolator = new Interpolator() {
+            @Override
+            public float getInterpolation(float x) {
+                // Flash the flash view in and out quickly
+                if (x <= flashDurationPct) {
+                    return (float) Math.sin(Math.PI * (x / flashDurationPct));
+                }
+                return 0;
+            }
+        };
+        final Interpolator scaleInterpolator = new Interpolator() {
+            @Override
+            public float getInterpolation(float x) {
+                // We start scaling when the flash is at it's peak
+                if (x < flashPeakDurationPct) {
+                    return 0;
+                }
+                return (x - flashDurationPct) / (1f - flashDurationPct);
+            }
+        };
+
+        Resources r = mContext.getResources();
+        if ((r.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES) {
+            mScreenshotView.getBackground().setTint(Color.BLACK);
+        } else {
+            mScreenshotView.getBackground().setTintList(null);
+        }
+
+        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+        anim.setDuration(SCREENSHOT_DROP_IN_DURATION);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mBackgroundView.setAlpha(0f);
+                mBackgroundView.setVisibility(View.VISIBLE);
+                mScreenshotView.setAlpha(0f);
+                mScreenshotView.setTranslationX(0f);
+                mScreenshotView.setTranslationY(0f);
+                mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale);
+                mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale);
+                mScreenshotView.setVisibility(View.VISIBLE);
+                mScreenshotFlash.setAlpha(0f);
+                mScreenshotFlash.setVisibility(View.VISIBLE);
+            }
+
+            @Override
+            public void onAnimationEnd(android.animation.Animator animation) {
+                mScreenshotFlash.setVisibility(View.GONE);
+            }
+        });
+        anim.addUpdateListener(new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float t = (Float) animation.getAnimatedValue();
+                float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)
+                        - scaleInterpolator.getInterpolation(t)
+                        * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);
+                mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
+                mScreenshotView.setAlpha(t);
+                mScreenshotView.setScaleX(scaleT);
+                mScreenshotView.setScaleY(scaleT);
+                mScreenshotFlash.setAlpha(flashAlphaInterpolator.getInterpolation(t));
+            }
+        });
+        return anim;
+    }
+
+    private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible,
+            boolean navBarVisible) {
+        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+        anim.setStartDelay(SCREENSHOT_DROP_OUT_DELAY);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mBackgroundView.setVisibility(View.GONE);
+                mScreenshotView.setVisibility(View.GONE);
+                mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
+            }
+        });
+
+        if (!statusBarVisible || !navBarVisible) {
+            // There is no status bar/nav bar, so just fade the screenshot away in place
+            anim.setDuration(SCREENSHOT_FAST_DROP_OUT_DURATION);
+            anim.addUpdateListener(new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    float t = (Float) animation.getAnimatedValue();
+                    float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
+                            - t * (SCREENSHOT_DROP_IN_MIN_SCALE
+                            - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
+                    mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
+                    mScreenshotView.setAlpha(1f - t);
+                    mScreenshotView.setScaleX(scaleT);
+                    mScreenshotView.setScaleY(scaleT);
+                }
+            });
+        } else {
+            // In the case where there is a status bar, animate to the origin of the bar (top-left)
+            final float scaleDurationPct = (float) SCREENSHOT_DROP_OUT_SCALE_DURATION
+                    / SCREENSHOT_DROP_OUT_DURATION;
+            final Interpolator scaleInterpolator = new Interpolator() {
+                @Override
+                public float getInterpolation(float x) {
+                    if (x < scaleDurationPct) {
+                        // Decelerate, and scale the input accordingly
+                        return (float) (1f - Math.pow(1f - (x / scaleDurationPct), 2f));
+                    }
+                    return 1f;
+                }
+            };
+
+            // Determine the bounds of how to scale
+            float halfScreenWidth = (w - 2f * mBgPadding) / 2f;
+            float halfScreenHeight = (h - 2f * mBgPadding) / 2f;
+            final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET;
+            final PointF finalPos = new PointF(
+                    -halfScreenWidth
+                            + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,
+                    -halfScreenHeight
+                            + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);
+
+            // Animate the screenshot to the status bar
+            anim.setDuration(SCREENSHOT_DROP_OUT_DURATION);
+            anim.addUpdateListener(new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    float t = (Float) animation.getAnimatedValue();
+                    float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
+                            - scaleInterpolator.getInterpolation(t)
+                            * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE);
+                    mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
+                    mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t));
+                    mScreenshotView.setScaleX(scaleT);
+                    mScreenshotView.setScaleY(scaleT);
+                    mScreenshotView.setTranslationX(t * finalPos.x);
+                    mScreenshotView.setTranslationY(t * finalPos.y);
+                }
+            });
+        }
+        return anim;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 29b96a9..4f045d5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -16,15 +16,21 @@
 
 package com.android.systemui.screenshot;
 
+import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
+
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_CORNER_FLOW;
+
 import android.app.Service;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.util.Log;
 import android.view.WindowManager;
 
@@ -36,9 +42,10 @@
     private static final String TAG = "TakeScreenshotService";
 
     private final GlobalScreenshot mScreenshot;
+    private final GlobalScreenshotLegacy mScreenshotLegacy;
     private final UserManager mUserManager;
 
-    private Handler mHandler = new Handler() {
+    private Handler mHandler = new Handler(Looper.myLooper()) {
         @Override
         public void handleMessage(Message msg) {
             final Messenger callback = msg.replyTo;
@@ -59,12 +66,24 @@
                 return;
             }
 
+            // TODO (mkephart): clean up once notifications flow is fully deprecated
+            boolean useCornerFlow = DeviceConfig.getBoolean(
+                    NAMESPACE_SYSTEMUI, SCREENSHOT_CORNER_FLOW, false);
             switch (msg.what) {
                 case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
-                    mScreenshot.takeScreenshot(finisher, msg.arg1 > 0, msg.arg2 > 0);
+                    if (useCornerFlow) {
+                        mScreenshot.takeScreenshot(finisher);
+                    } else {
+                        mScreenshotLegacy.takeScreenshot(finisher, msg.arg1 > 0, msg.arg2 > 0);
+                    }
                     break;
                 case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
-                    mScreenshot.takeScreenshotPartial(finisher, msg.arg1 > 0, msg.arg2 > 0);
+                    if (useCornerFlow) {
+                        mScreenshot.takeScreenshotPartial(finisher);
+                    } else {
+                        mScreenshotLegacy.takeScreenshotPartial(
+                                finisher, msg.arg1 > 0, msg.arg2 > 0);
+                    }
                     break;
                 default:
                     Log.d(TAG, "Invalid screenshot option: " + msg.what);
@@ -73,8 +92,10 @@
     };
 
     @Inject
-    public TakeScreenshotService(GlobalScreenshot globalScreenshot, UserManager userManager) {
+    public TakeScreenshotService(GlobalScreenshot globalScreenshot,
+            GlobalScreenshotLegacy globalScreenshotLegacy, UserManager userManager) {
         mScreenshot = globalScreenshot;
+        mScreenshotLegacy = globalScreenshotLegacy;
         mUserManager = userManager;
     }
 
@@ -86,6 +107,7 @@
     @Override
     public boolean onUnbind(Intent intent) {
         if (mScreenshot != null) mScreenshot.stopScreenshot();
+        if (mScreenshotLegacy != null) mScreenshotLegacy.stopScreenshot();
         return true;
     }
 }