Merge "Binding Pwr+VolDown to take screenshot."
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6d8eab6..f42cbbf 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -25,6 +25,11 @@
             android:exported="true"
             />
 
+        <!-- started from PhoneWindowManager
+             TODO: Should have an android:permission attribute -->
+        <service android:name=".screenshot.TakeScreenshotService"
+            android:exported="false" />
+
         <activity android:name=".usb.UsbPreferenceActivity"
              android:theme="@*android:style/Theme.Holo.Dialog.Alert"
              android:excludeFromRecents="true">
diff --git a/packages/SystemUI/res/drawable-hdpi/global_screenshot_background.9.png b/packages/SystemUI/res/drawable-hdpi/global_screenshot_background.9.png
new file mode 100644
index 0000000..e14111d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/global_screenshot_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/global_screenshot_background.9.png b/packages/SystemUI/res/drawable-mdpi/global_screenshot_background.9.png
new file mode 100644
index 0000000..e14111d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/global_screenshot_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
new file mode 100644
index 0000000..6cb8799
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -0,0 +1,40 @@
+<?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_background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#FF000000"
+        android:visibility="gone" />
+    <FrameLayout
+        android:id="@+id/global_screenshot_container"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/global_screenshot_background"
+        android:visibility="gone">
+        <ImageView android:id="@+id/global_screenshot"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:adjustViewBounds="true" />
+    </FrameLayout>
+    <ImageView android:id="@+id/global_screenshot_flash"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#FFFFFFFF"
+        android:visibility="gone" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 86e0cd0..70f9b75 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -165,4 +165,9 @@
     <string name="use_ptp_button_title">Mount as a camera (PTP)</string>
     <!-- Label for the installer CD image option in UsbPreferenceActivity. [CHAR LIMIT=50] -->
     <string name="installer_cd_button_title">Install Android File Transfer application for Mac</string>
+
+    <!-- toast message displayed when a screenshot is saved to the Gallery. -->
+    <string name="screenshot_saving_toast">Screenshot saved to Gallery</string>
+    <!-- toast message displayed when we fail to take a screenshot. -->
+    <string name="screenshot_failed_toast">Could not save screenshot</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
new file mode 100644
index 0000000..83a5578
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -0,0 +1,384 @@
+/*
+ * 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 android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.Activity;
+import android.content.ContentValues;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.PixelFormat;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.ServiceManager;
+import android.provider.MediaStore;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.systemui.R;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.Thread;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * POD used in the AsyncTask which saves an image in the background.
+ */
+class SaveImageInBackgroundData {
+    Context context;
+    Bitmap image;
+    int result;
+}
+
+/**
+ * An AsyncTask that saves an image to the media store in the background.
+ */
+class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void,
+        SaveImageInBackgroundData> {
+    private static final String TAG = "SaveImageInBackgroundTask";
+    private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
+    private static final String SCREENSHOT_FILE_PATH_TEMPLATE = "%s/%s/Screenshot_%s-%d.png";
+
+    @Override
+    protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {
+        if (params.length != 1) return null;
+
+        Context context = params[0].context;
+        Bitmap image = params[0].image;
+
+        try{
+            long currentTime = System.currentTimeMillis();
+            String date = new SimpleDateFormat("MM-dd-yy-kk-mm-ss").format(new Date(currentTime));
+            String imageDir = Environment.getExternalStoragePublicDirectory(
+                    Environment.DIRECTORY_PICTURES).getAbsolutePath();
+            String imageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE,
+                    imageDir, SCREENSHOTS_DIR_NAME,
+                    date, currentTime % 1000);
+
+            // Save the screenshot to the MediaStore
+            ContentValues values = new ContentValues();
+            values.put(MediaStore.Images.ImageColumns.DATA, imageFilePath);
+            values.put(MediaStore.Images.ImageColumns.TITLE, "Screenshot");
+            values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, "Screenshot");
+            values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, currentTime);
+            values.put(MediaStore.Images.ImageColumns.DATE_ADDED, currentTime);
+            values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, currentTime);
+            values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
+            Uri uri = context.getContentResolver().insert(
+                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+
+            OutputStream out = context.getContentResolver().openOutputStream(uri);
+            image.compress(Bitmap.CompressFormat.PNG, 100, out);
+            out.flush();
+            out.close();
+
+            params[0].result = 0;
+        }catch(IOException e){
+            params[0].result = 1;
+        }
+
+        return params[0];
+    };
+
+    @Override
+    protected void onPostExecute(SaveImageInBackgroundData params) {
+        if (params.result > 0) {
+            // Show a message that we've failed to save the image to disk
+            Toast.makeText(params.context, R.string.screenshot_failed_toast,
+                    Toast.LENGTH_SHORT).show();
+        } else {
+            // Show a message that we've saved the screenshot to disk
+            Toast.makeText(params.context, R.string.screenshot_saving_toast,
+                    Toast.LENGTH_SHORT).show();
+        }
+    };
+}
+
+/**
+ * TODO:
+ *   - Performance when over gl surfaces? Ie. Gallery
+ *   - what do we say in the Toast? Which icon do we get if the user uses another
+ *     type of gallery?
+ */
+class GlobalScreenshot {
+    private static final String TAG = "GlobalScreenshot";
+    private static final int SCREENSHOT_FADE_IN_DURATION = 900;
+    private static final int SCREENSHOT_FADE_OUT_DELAY = 1000;
+    private static final int SCREENSHOT_FADE_OUT_DURATION = 450;
+    private static final int TOAST_FADE_IN_DURATION = 500;
+    private static final int TOAST_FADE_OUT_DELAY = 1000;
+    private static final int TOAST_FADE_OUT_DURATION = 500;
+    private static final float BACKGROUND_ALPHA = 0.65f;
+    private static final float SCREENSHOT_SCALE = 0.85f;
+    private static final float SCREENSHOT_MIN_SCALE = 0.7f;
+    private static final float SCREENSHOT_ROTATION = -6.75f; // -12.5f;
+
+    private Context mContext;
+    private LayoutInflater mLayoutInflater;
+    private IWindowManager mIWindowManager;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mWindowLayoutParams;
+    private Display mDisplay;
+    private DisplayMetrics mDisplayMetrics;
+    private Matrix mDisplayMatrix;
+
+    private Bitmap mScreenBitmap;
+    private View mScreenshotLayout;
+    private ImageView mBackgroundView;
+    private FrameLayout mScreenshotContainerView;
+    private ImageView mScreenshotView;
+
+    private AnimatorSet mScreenshotAnimation;
+
+    // General use cubic interpolator
+    final TimeInterpolator mCubicInterpolator = new TimeInterpolator() {
+        public float getInterpolation(float t) {
+            return t*t*t;
+        }
+    };
+    // The interpolator used to control the background alpha at the start of the animation
+    final TimeInterpolator mBackgroundViewAlphaInterpolator = new TimeInterpolator() {
+        public float getInterpolation(float t) {
+            float tStep = 0.35f;
+            if (t < tStep) {
+                return t * (1f / tStep);
+            } else {
+                return 1f;
+            }
+        }
+    };
+
+    /**
+     * @param context everything needs a context :(
+     */
+    public GlobalScreenshot(Context context) {
+        mContext = context;
+        mLayoutInflater = (LayoutInflater)
+                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        // Inflate the screenshot layout
+        mDisplayMetrics = new DisplayMetrics();
+        mDisplayMatrix = new Matrix();
+        mScreenshotLayout = mLayoutInflater.inflate(R.layout.global_screenshot, null);
+        mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
+        mScreenshotContainerView = (FrameLayout) mScreenshotLayout.findViewById(R.id.global_screenshot_container);
+        mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
+        mScreenshotLayout.setFocusable(true);
+        mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                // Intercept and ignore all touch events
+                return true;
+            }
+        });
+
+        // Setup the window that we are going to use
+        mIWindowManager = IWindowManager.Stub.asInterface(
+                ServiceManager.getService(Context.WINDOW_SERVICE));
+        mWindowLayoutParams = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
+                WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
+                WindowManager.LayoutParams.FLAG_FULLSCREEN
+                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED_SYSTEM
+                    | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
+                PixelFormat.TRANSLUCENT);
+        mWindowLayoutParams.token = new Binder();
+        mWindowLayoutParams.setTitle("ScreenshotAnimation");
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        mDisplay = mWindowManager.getDefaultDisplay();
+    }
+
+    /**
+     * Creates a new worker thread and saves the screenshot to the media store.
+     */
+    private void saveScreenshotInWorkerThread() {
+        SaveImageInBackgroundData data = new SaveImageInBackgroundData();
+        data.context = mContext;
+        data.image = mScreenBitmap;
+        new SaveImageInBackgroundTask().execute(data);
+    }
+
+    /**
+     * @return the current display rotation in degrees
+     */
+    private float getDegreesForRotation(int value) {
+        switch (value) {
+        case Surface.ROTATION_90:
+            return 90f;
+        case Surface.ROTATION_180:
+            return 180f;
+        case Surface.ROTATION_270:
+            return 270f;
+        }
+        return 0f;
+    }
+
+    /**
+     * Takes a screenshot of the current display and shows an animation.
+     */
+    void takeScreenshot() {
+        // We need to orient the screenshot correctly (and the Surface api seems to take screenshots
+        // only in the natural orientation of the device :!)
+        mDisplay.getRealMetrics(mDisplayMetrics);
+        float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
+        float degrees = getDegreesForRotation(mDisplay.getRotation());
+        boolean requiresRotation = (degrees > 0);
+        if (requiresRotation) {
+            // Get the dimensions of the device in its native orientation
+            mDisplayMatrix.reset();
+            mDisplayMatrix.preRotate(-degrees);
+            mDisplayMatrix.mapPoints(dims);
+            dims[0] = Math.abs(dims[0]);
+            dims[1] = Math.abs(dims[1]);
+        }
+        mScreenBitmap = Surface.screenshot((int) dims[0], (int) dims[1]);
+        if (requiresRotation) {
+            // Rotate the screenshot to the current orientation
+            Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,
+                    mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
+            Canvas c = new Canvas(ss);
+            c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
+            c.rotate(360f - degrees);
+            c.translate(-dims[0] / 2, -dims[1] / 2);
+            c.drawBitmap(mScreenBitmap, 0, 0, null);
+            mScreenBitmap = ss;
+        }
+
+        // If we couldn't take the screenshot, notify the user
+        if (mScreenBitmap == null) {
+            Toast.makeText(mContext, R.string.screenshot_failed_toast,
+                    Toast.LENGTH_SHORT).show();
+            return;
+        }
+
+        // Start the post-screenshot animation
+        startAnimation();
+    }
+
+
+    /**
+     * Starts the animation after taking the screenshot
+     */
+    private void startAnimation() {
+        // Add the view for the animation
+        mScreenshotView.setImageBitmap(mScreenBitmap);
+        mScreenshotLayout.requestFocus();
+
+        // Setup the animation with the screenshot just taken
+        if (mScreenshotAnimation != null) {
+            mScreenshotAnimation.end();
+        }
+
+        mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+        ValueAnimator screenshotFadeInAnim = createScreenshotFadeInAnimation();
+        ValueAnimator screenshotFadeOutAnim = createScreenshotFadeOutAnimation();
+        mScreenshotAnimation = new AnimatorSet();
+        mScreenshotAnimation.play(screenshotFadeInAnim).before(screenshotFadeOutAnim);
+        mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Save the screenshot once we have a bit of time now
+                saveScreenshotInWorkerThread();
+
+                mWindowManager.removeView(mScreenshotLayout);
+            }
+        });
+        mScreenshotAnimation.start();
+    }
+    private ValueAnimator createScreenshotFadeInAnimation() {
+        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+        anim.setInterpolator(mCubicInterpolator);
+        anim.setDuration(SCREENSHOT_FADE_IN_DURATION);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mBackgroundView.setVisibility(View.VISIBLE);
+                mScreenshotContainerView.setVisibility(View.VISIBLE);
+            }
+        });
+        anim.addUpdateListener(new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float t = ((Float) animation.getAnimatedValue()).floatValue();
+                mBackgroundView.setAlpha(mBackgroundViewAlphaInterpolator.getInterpolation(t) *
+                        BACKGROUND_ALPHA);
+                float scaleT = SCREENSHOT_SCALE + (1f - t) * SCREENSHOT_SCALE;
+                mScreenshotContainerView.setAlpha(t*t*t*t);
+                mScreenshotContainerView.setScaleX(scaleT);
+                mScreenshotContainerView.setScaleY(scaleT);
+                mScreenshotContainerView.setRotation(t * SCREENSHOT_ROTATION);
+            }
+        });
+        return anim;
+    }
+    private ValueAnimator createScreenshotFadeOutAnimation() {
+        ValueAnimator anim = ValueAnimator.ofFloat(1f, 0f);
+        anim.setInterpolator(mCubicInterpolator);
+        anim.setStartDelay(SCREENSHOT_FADE_OUT_DELAY);
+        anim.setDuration(SCREENSHOT_FADE_OUT_DURATION);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mBackgroundView.setVisibility(View.GONE);
+                mScreenshotContainerView.setVisibility(View.GONE);
+            }
+        });
+        anim.addUpdateListener(new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float t = ((Float) animation.getAnimatedValue()).floatValue();
+                float scaleT = SCREENSHOT_MIN_SCALE +
+                        t*(SCREENSHOT_SCALE - SCREENSHOT_MIN_SCALE);
+                mScreenshotContainerView.setAlpha(t);
+                mScreenshotContainerView.setScaleX(scaleT);
+                mScreenshotContainerView.setScaleY(scaleT);
+                mBackgroundView.setAlpha(t * t * BACKGROUND_ALPHA);
+            }
+        });
+        return anim;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
new file mode 100644
index 0000000..35eaedf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -0,0 +1,50 @@
+/*
+ * 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 android.app.Service;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class TakeScreenshotService extends Service {
+    private static final String TAG = "TakeScreenshotService";
+
+    private static GlobalScreenshot mScreenshot;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (mScreenshot == null) {
+            mScreenshot = new GlobalScreenshot(this);
+        }
+        mScreenshot.takeScreenshot();
+        return null;
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b52e7e1..ad6cebb 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -28,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
@@ -372,6 +373,10 @@
     // What we do when the user long presses on home
     private int mLongPressOnHomeBehavior = -1;
 
+    // Screenshot trigger states
+    private boolean mVolumeDownTriggered;
+    private boolean mPowerDownTriggered;
+
     ShortcutManager mShortcutManager;
     PowerManager.WakeLock mBroadcastWakeLock;
 
@@ -2339,6 +2344,26 @@
         }
     }
 
+    private void takeScreenshot() {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                ComponentName cn = new ComponentName("com.android.systemui",
+                        "com.android.systemui.screenshot.TakeScreenshotService");
+                Intent intent = new Intent();
+                intent.setComponent(cn);
+                ServiceConnection conn = new ServiceConnection() {
+                    @Override
+                    public void onServiceConnected(ComponentName name, IBinder service) {}
+                    @Override
+                    public void onServiceDisconnected(ComponentName name) {}
+                };
+                mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+                mContext.unbindService(conn);
+            }
+        });
+    }
+
     /** {@inheritDoc} */
     @Override
     public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
@@ -2398,6 +2423,24 @@
         // Handle special keys.
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_DOWN:
+                if (down) {
+                    // If the power key down was already triggered, take the screenshot
+                    if (mPowerDownTriggered) {
+                        // Dismiss the power-key longpress
+                        mHandler.removeCallbacks(mPowerLongPress);
+                        mPowerKeyHandled = true;
+
+                        // Take the screenshot
+                        takeScreenshot();
+
+                        // Prevent the event from being passed through to the current activity
+                        result &= ~ACTION_PASS_TO_USER;
+                        break;
+                    }
+                    mVolumeDownTriggered = true;
+                } else {
+                    mVolumeDownTriggered = false;
+                }
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
                 if (down) {
@@ -2478,6 +2521,18 @@
             case KeyEvent.KEYCODE_POWER: {
                 result &= ~ACTION_PASS_TO_USER;
                 if (down) {
+                    // If the volume down key has been triggered, then just take the screenshot
+                    if (mVolumeDownTriggered) {
+                        // Take the screenshot
+                        takeScreenshot();
+                        mPowerKeyHandled = true;
+
+                        // Prevent the event from being passed through to the current activity
+                        break;
+                    }
+                    mPowerDownTriggered = true;
+
+
                     ITelephony telephonyService = getTelephonyService();
                     boolean hungUp = false;
                     if (telephonyService != null) {
@@ -2499,6 +2554,7 @@
                     }
                     interceptPowerKeyDown(!isScreenOn || hungUp);
                 } else {
+                    mPowerDownTriggered = false;
                     if (interceptPowerKeyUp(canceled)) {
                         result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
                     }