android 关于屏幕截屏的几种办法

来源:互联网 发布:吴昕开的淘宝店叫什么 编辑:程序博客网 时间:2024/06/10 14:57

年末较闲,就上个星期查找各方面的资料关于android截图事情,自已也测试一些代码,已改改进或者优化。接下来进行总结一下。其实,如果真正android系统截屏是需要root权限的。但要用户使用都root,似乎不可能,体验性太差了。这期间我稍微观察了QQ的截图。QQ的截图是摇一摇截图当前屏幕,这个是不需要root权限的。然而,如果你要截图页面不是当前页面,就需要root权限。可以使用360超级root尝试一下。

本文demo下载地址:http://download.csdn.net/detail/qq_16064871/9420810

1、直接使用getWindow().getDecorView().getRootView()

直接使用getWindow().getDecorView().getRootView()是获取当前屏幕的activity。然而对于系统状态栏的信息是截不了,出现一条空白的。如下图:



主要到没,有一条白色边就是系统状态栏。看一下代码,很简单都加了注释了。

//这种方法状态栏是空白,显示不了状态栏的信息private void saveCurrentImage()      {          //获取当前屏幕的大小int width = getWindow().getDecorView().getRootView().getWidth();        int height = getWindow().getDecorView().getRootView().getHeight();        //生成相同大小的图片        Bitmap temBitmap = Bitmap.createBitmap( width, height, Config.ARGB_8888 );            //找到当前页面的跟布局        View view =  getWindow().getDecorView().getRootView();        //设置缓存        view.setDrawingCacheEnabled(true);        view.buildDrawingCache();        //从缓存中获取当前屏幕的图片        temBitmap = view.getDrawingCache(); //输出到sd卡if (FileIOUtil.getExistStorage()) {FileIOUtil.GetInstance().onFolderAnalysis(FileIOUtil.GetInstance().getFilePathAndName());        File file = new File(FileIOUtil.GetInstance().getFilePathAndName());   try {            if (!file.exists()) {                  file.createNewFile();              }  FileOutputStream foStream = new FileOutputStream(file); temBitmap.compress(Bitmap.CompressFormat.PNG, 100, foStream); foStream.flush();   foStream.close();} catch (Exception e) {Log.i("Show", e.toString());}}    }

2、自定义view控件的截图

自定义view控件都是继承view的吗,那么就有可以获取宽度,高度。生成图片,把它绘制出来的。我拿了直接写的自定义随机验证码的例子来截图。


    //保存自定义view的截图private void saveCustomViewBitmap() {//获取自定义view图片的大小Bitmap temBitmap = Bitmap.createBitmap(mCodeView.getWidth(), mCodeView.getHeight(), Config.ARGB_8888);//使用Canvas,调用自定义view控件的onDraw方法,绘制图片Canvas canvas = new Canvas(temBitmap);mCodeView.onDraw(canvas);//输出到sd卡if (FileIOUtil.getExistStorage()) {FileIOUtil.GetInstance().onFolderAnalysis(FileIOUtil.GetInstance().getFilePathAndName());        File file = new File(FileIOUtil.GetInstance().getFilePathAndName());   try {            if (!file.exists()) {                  file.createNewFile();              }  FileOutputStream foStream = new FileOutputStream(file); temBitmap.compress(Bitmap.CompressFormat.PNG, 100, foStream); foStream.flush();   foStream.close(); Toast.makeText(MainActivity.this, "截屏文件已保存至" + FileIOUtil.GetInstance().getFilePathAndName(), Toast.LENGTH_LONG).show(); } catch (Exception e) {Log.i("Show", e.toString());}}}
有人根据这种思路,自定义整个布局的view,然后来截图。也是够拼的,我有点不赞成这样使用。

3、基于android ddmlib截屏

这个是java写的一个类,入口是mian函数。那么这种实现方式是要android连接着电脑,还需要android设备调试。这种不多说,搞android开发都懂。太麻烦了,我们也不使用。

package com.example.screenshot;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import com.android.ddmlib.AdbCommandRejectedException;import com.android.ddmlib.AndroidDebugBridge;import com.android.ddmlib.IDevice;import com.android.ddmlib.RawImage;import com.android.ddmlib.TimeoutException;public class ScreenShoddmlib {private BufferedImage image = null;   /**   * @param args   */   public static void main(String[] args) {    // TODO Auto-generated method stub    AndroidDebugBridge.init(false); //    ScreenShoddmlib screenshot = new ScreenShoddmlib();    IDevice device = screenshot.getDevice();        for (int i = 0; i < 10; i++) {     Date date=new Date();     SimpleDateFormat df=new SimpleDateFormat("MM-dd-HH-mm-ss");      String nowTime = df.format(date);     screenshot.getScreenShot(device, "Robotium" + nowTime);     try {      Thread.sleep(1000);     } catch (InterruptedException e) {      // TODO Auto-generated catch block      e.printStackTrace();     }    }   }        public void getScreenShot(IDevice device,String filename) {    RawImage rawScreen = null;    try {     rawScreen = device.getScreenshot();    } catch (TimeoutException e) {     // TODO Auto-generated catch block     e.printStackTrace();    } catch (AdbCommandRejectedException e) {     // TODO Auto-generated catch block     e.printStackTrace();    } catch (IOException e) {     // TODO Auto-generated catch block     e.printStackTrace();    }    if (rawScreen != null) {     Boolean landscape = false;     int width2 = landscape ? rawScreen.height : rawScreen.width;     int height2 = landscape ? rawScreen.width : rawScreen.height;     if (image == null) {      image = new BufferedImage(width2, height2,        BufferedImage.TYPE_INT_RGB);     } else {      if (image.getHeight() != height2 || image.getWidth() != width2) {       image = new BufferedImage(width2, height2,         BufferedImage.TYPE_INT_RGB);      }     }     int index = 0;     int indexInc = rawScreen.bpp >> 3;     for (int y = 0; y < rawScreen.height; y++) {      for (int x = 0; x < rawScreen.width; x++, index += indexInc) {       int value = rawScreen.getARGB(index);       if (landscape)        image.setRGB(y, rawScreen.width - x - 1, value);       else        image.setRGB(x, y, value);      }     }     try {      ImageIO.write((RenderedImage) image, "PNG", new File("D:/"        + filename + ".jpg"));     } catch (IOException e) {      // TODO Auto-generated catch block      e.printStackTrace();     }    }   }     /**   * 获取得到device对象   * @return   */   private IDevice getDevice(){    IDevice device;    AndroidDebugBridge bridge = AndroidDebugBridge      .createBridge("adb", true);//如果代码有问题请查看API,修改此处的参数值试一下    waitDevicesList(bridge);    IDevice devices[] = bridge.getDevices();    device = devices[0];    return device;   }      /**   * 等待查找device   * @param bridge   */   private void waitDevicesList(AndroidDebugBridge bridge) {    int count = 0;    while (bridge.hasInitialDeviceList() == false) {     try {      Thread.sleep(500);       count++;     } catch (InterruptedException e) {     }     if (count > 240) {      System.err.print("等待获取设备超时");      break;     }    }  }

4、使用adb命令

需要系统权限,在APK中调用“adb shell screencap -pfilepath” 命令

需要获得系统权限:1、 在AndroidManifest.xml文件中添加 <uses-permissionandroid:name="android.permission.READ_FRAME_BUFFER"/>
                     2、修改APK为系统权限,将APK放到源码中编译, 修改Android.mk     LOCAL_CERTIFICATE := platform
在这里我要说一下,搞过jni调用就知道Android.mk的作用。此举也是麻烦,效果也不是很好。

public void takeScreenShot(){     String mSavedPath = Environment.getExternalStorageDirectory()+File. separator + "screenshot.png" ; try {                                Runtime. getRuntime().exec("screencap -p " + mSavedPath);     } catch (Exception e) {            e.printStackTrace();     } 

5、看一下系统截屏是怎样的

相信大家都知道,三星的机子是同时按下 home键 + 电源键 3秒截图。

如果没有home键的机子是按下 音量键向下那个 + 电源键 3秒截图的。

获取物理键盘按下的源码:PhoneWindowManager.java

       // Handle special keys.        switch (keyCode) {            case KeyEvent.KEYCODE_VOLUME_DOWN:            case KeyEvent.KEYCODE_VOLUME_UP:            case KeyEvent.KEYCODE_VOLUME_MUTE: {                if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {                    if (down) {                        if (isScreenOn && !mVolumeDownKeyTriggered                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {                            mVolumeDownKeyTriggered = true;                            mVolumeDownKeyTime = event.getDownTime();                            mVolumeDownKeyConsumedByScreenshotChord = false;                            cancelPendingPowerKeyAction();                            interceptScreenshotChord();                        }                    } else {                        mVolumeDownKeyTriggered = false;                        cancelPendingScreenshotChordAction();                    }                } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {                    if (down) {                        if (isScreenOn && !mVolumeUpKeyTriggered                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {                            mVolumeUpKeyTriggered = true;                            cancelPendingPowerKeyAction();                            cancelPendingScreenshotChordAction();                        }                    } else {                        mVolumeUpKeyTriggered = false;                        cancelPendingScreenshotChordAction();                    }                }                if (down) {                    ITelephony telephonyService = getTelephonyService();                    if (telephonyService != null) {                        try {                            if (telephonyService.isRinging()) {                                // If an incoming call is ringing, either VOLUME key means                                // "silence ringer".  We handle these keys here, rather than                                // in the InCallScreen, to make sure we'll respond to them                                // even if the InCallScreen hasn't come to the foreground yet.                                // Look for the DOWN event here, to agree with the "fallback"                                // behavior in the InCallScreen.                                Log.i(TAG, "interceptKeyBeforeQueueing:"                                      + " VOLUME key-down while ringing: Silence ringer!");                                // Silence the ringer.  (It's safe to call this                                // even if the ringer has already been silenced.)                                telephonyService.silenceRinger();                                // And *don't* pass this key thru to the current activity                                // (which is probably the InCallScreen.)                                result &= ~ACTION_PASS_TO_USER;                                break;                            }                            if (telephonyService.isOffhook()                                    && (result & ACTION_PASS_TO_USER) == 0) {                                // If we are in call but we decided not to pass the key to                                // the application, handle the volume change here.                                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);                                break;                            }                        } catch (RemoteException ex) {                            Log.w(TAG, "ITelephony threw RemoteException", ex);                        }                    }                    if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {                        // If music is playing but we decided not to pass the key to the                        // application, handle the volume change here.                        handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);                        break;                    }                }                break;            }            case KeyEvent.KEYCODE_ENDCALL: {                result &= ~ACTION_PASS_TO_USER;                if (down) {                    ITelephony telephonyService = getTelephonyService();                    boolean hungUp = false;                    if (telephonyService != null) {                        try {                            hungUp = telephonyService.endCall();                        } catch (RemoteException ex) {                            Log.w(TAG, "ITelephony threw RemoteException", ex);                        }                    }                    interceptPowerKeyDown(!isScreenOn || hungUp);                } else {                    if (interceptPowerKeyUp(canceled)) {                        if ((mEndcallBehavior                                & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {                            if (goHome()) {                                break;                            }                        }                        if ((mEndcallBehavior                                & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {                            result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;                        }                    }                }                break;            }            case KeyEvent.KEYCODE_POWER: {                result &= ~ACTION_PASS_TO_USER;                if (down) {                    if (isScreenOn && !mPowerKeyTriggered                            && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {                        mPowerKeyTriggered = true;                        mPowerKeyTime = event.getDownTime();                        interceptScreenshotChord();                    }                    ITelephony telephonyService = getTelephonyService();                    boolean hungUp = false;                    if (telephonyService != null) {                        try {                            if (telephonyService.isRinging()) {                                // Pressing Power while there's a ringing incoming                                // call should silence the ringer.                                telephonyService.silenceRinger();                            } else if ((mIncallPowerBehavior                                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0                                    && telephonyService.isOffhook()) {                                // Otherwise, if "Power button ends call" is enabled,                                // the Power button will hang up any current active call.                                hungUp = telephonyService.endCall();                            }                        } catch (RemoteException ex) {                            Log.w(TAG, "ITelephony threw RemoteException", ex);                        }                    }                    interceptPowerKeyDown(!isScreenOn || hungUp                            || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);                } else {                    mPowerKeyTriggered = false;                    cancelPendingScreenshotChordAction();                    if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {                        result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;                    }                    mPendingPowerKeyUpCanceled = false;                }                break;            }


响应截屏的方法:

    private void interceptScreenshotChord() {        if (mScreenshotChordEnabled                && mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) {            final long now = SystemClock.uptimeMillis();            if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS                    && now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {                mVolumeDownKeyConsumedByScreenshotChord = true;                cancelPendingPowerKeyAction();                mHandler.postDelayed(mScreenshotChordLongPress, getScreenshotChordLongPressDelay());            }        }    }    private long getScreenshotChordLongPressDelay() {        if (mKeyguardMediator.isShowing()) {            // Double the time it takes to take a screenshot from the keyguard            return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *                    ViewConfiguration.getGlobalActionKeyTimeout());        } else {            return ViewConfiguration.getGlobalActionKeyTimeout();        }    }

接受响应的服务

    private final Runnable mScreenshotChordLongPress = new Runnable() {        public void run() {            takeScreenshot();        }    };

    private void takeScreenshot() {        synchronized (mScreenshotLock) {            if (mScreenshotConnection != null) {                return;            }            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) {                    synchronized (mScreenshotLock) {                        if (mScreenshotConnection != this) {                            return;                        }                        Messenger messenger = new Messenger(service);                        Message msg = Message.obtain(null, 1);                        final ServiceConnection myConn = this;                        Handler h = new Handler(mHandler.getLooper()) {                            @Override                            public void handleMessage(Message msg) {                                synchronized (mScreenshotLock) {                                    if (mScreenshotConnection == myConn) {                                        mContext.unbindService(mScreenshotConnection);                                        mScreenshotConnection = null;                                        mHandler.removeCallbacks(mScreenshotTimeout);                                    }                                }                            }                        };                        msg.replyTo = new Messenger(h);                        msg.arg1 = msg.arg2 = 0;                        if (mStatusBar != null && mStatusBar.isVisibleLw())                            msg.arg1 = 1;                        if (mNavigationBar != null && mNavigationBar.isVisibleLw())                            msg.arg2 = 1;                        try {                            messenger.send(msg);                        } catch (RemoteException e) {                        }                    }                }                @Override                public void onServiceDisconnected(ComponentName name) {}            };            if (mContext.bindService(                    intent, conn, Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) {                mScreenshotConnection = conn;                mHandler.postDelayed(mScreenshotTimeout, 10000);            }        }    }

启动时这个服务 ComponentName cn = new ComponentName("com.android.systemui", "com.android.systemui.screenshot.TakeScreenshotService");

package com.android.systemui.screenshot;import android.app.Service;import android.content.Intent;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;public class TakeScreenshotService extends Service {    private static final String TAG = "TakeScreenshotService";    private static GlobalScreenshot mScreenshot;    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case 1:                    final Messenger callback = msg.replyTo;                    if (mScreenshot == null) {                        mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);                    }                    mScreenshot.takeScreenshot(new Runnable() {                        @Override public void run() {                            Message reply = Message.obtain(null, 1);                            try {                                callback.send(reply);                            } catch (RemoteException e) {                            }                        }                    }, msg.arg1 > 0, msg.arg2 > 0);            }        }    };    @Override    public IBinder onBind(Intent intent) {        return new Messenger(mHandler).getBinder();    }
再往下就是底层库,需要编译出来才能看得到了。这些就先不研究了。

6、还有部分系统源码是截图的

/* * 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.ValueAnimator;import android.animation.ValueAnimator.AnimatorUpdateListener;import android.app.Notification;import android.app.Notification.BigPictureStyle;import android.app.NotificationManager;import android.app.PendingIntent;import android.content.ContentResolver;import android.content.ContentValues;import android.content.Context;import android.content.Intent;import android.content.res.Resources;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.ColorMatrix;import android.graphics.ColorMatrixColorFilter;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PixelFormat;import android.graphics.PointF;import android.media.MediaActionSound;import android.net.Uri;import android.os.AsyncTask;import android.os.Environment;import android.os.Process;import android.provider.MediaStore;import android.util.DisplayMetrics;import android.view.Display;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.view.animation.Interpolator;import android.widget.ImageView;import com.android.systemui.R;import java.io.File;import java.io.OutputStream;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;    Uri imageUri;    Runnable finisher;    int iconSize;    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 SCREENSHOTS_DIR_NAME = "Screenshots";    private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";    private static final String SCREENSHOT_FILE_PATH_TEMPLATE = "%s/%s/%s";    private int mNotificationId;    private NotificationManager mNotificationManager;    private Notification.Builder mNotificationBuilder;    private String mImageFileName;    private String mImageFilePath;    private long mImageTime;    private BigPictureStyle mNotificationStyle;    // WORKAROUND: We want the same notification across screenshots that we update so that we don't    // spam a user's notification drawer.  However, we only show the ticker for the saving state    // and if the ticker text is the same as the previous notification, then it will not show. So    // for now, we just add and remove a space from the ticker text to trigger the animation when    // necessary.    private static boolean mTickerAddSpace;    SaveImageInBackgroundTask(Context context, SaveImageInBackgroundData data,            NotificationManager nManager, int nId) {        Resources r = context.getResources();        // Prepare all the output metadata        mImageTime = System.currentTimeMillis();        String imageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(mImageTime));        String imageDir = Environment.getExternalStoragePublicDirectory(                Environment.DIRECTORY_PICTURES).getAbsolutePath();        mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);        mImageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE, imageDir,                SCREENSHOTS_DIR_NAME, mImageFileName);        // Create the large notification icon        int imageWidth = data.image.getWidth();        int imageHeight = data.image.getHeight();        int iconSize = data.iconSize;        final int shortSide = imageWidth < imageHeight ? imageWidth : imageHeight;        Bitmap preview = Bitmap.createBitmap(shortSide, shortSide, data.image.getConfig());        Canvas c = new Canvas(preview);        Paint paint = new Paint();        ColorMatrix desat = new ColorMatrix();        desat.setSaturation(0.25f);        paint.setColorFilter(new ColorMatrixColorFilter(desat));        Matrix matrix = new Matrix();        matrix.postTranslate((shortSide - imageWidth) / 2,                            (shortSide - imageHeight) / 2);        c.drawBitmap(data.image, matrix, paint);        c.drawColor(0x40FFFFFF);        Bitmap croppedIcon = Bitmap.createScaledBitmap(preview, iconSize, iconSize, true);        // Show the intermediate notification        mTickerAddSpace = !mTickerAddSpace;        mNotificationId = nId;        mNotificationManager = nManager;        mNotificationBuilder = new Notification.Builder(context)            .setTicker(r.getString(R.string.screenshot_saving_ticker)                    + (mTickerAddSpace ? " " : ""))            .setContentTitle(r.getString(R.string.screenshot_saving_title))            .setContentText(r.getString(R.string.screenshot_saving_text))            .setSmallIcon(R.drawable.stat_notify_image)            .setWhen(System.currentTimeMillis());        mNotificationStyle = new Notification.BigPictureStyle()            .bigPicture(preview);        mNotificationBuilder.setStyle(mNotificationStyle);        Notification n = mNotificationBuilder.build();        n.flags |= Notification.FLAG_NO_CLEAR;        mNotificationManager.notify(nId, n);        // On the tablet, the large icon makes the notification appear as if it is clickable (and        // on small devices, the large icon is not shown) so defer showing the large icon until        // we compose the final post-save notification below.        mNotificationBuilder.setLargeIcon(croppedIcon);        // But we still don't set it for the expanded view, allowing the smallIcon to show here.        mNotificationStyle.bigLargeIcon(null);    }    @Override    protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {        if (params.length != 1) return null;        // By default, AsyncTask sets the worker thread to have background thread priority, so bump        // it back up so that we save a little quicker.        Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);        Context context = params[0].context;        Bitmap image = params[0].image;        Resources r = context.getResources();        try {            // Save the screenshot to the MediaStore            ContentValues values = new ContentValues();            ContentResolver resolver = context.getContentResolver();            values.put(MediaStore.Images.ImageColumns.DATA, mImageFilePath);            values.put(MediaStore.Images.ImageColumns.TITLE, mImageFileName);            values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, mImageFileName);            values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, mImageTime);            values.put(MediaStore.Images.ImageColumns.DATE_ADDED, mImageTime);            values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, mImageTime);            values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");            Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);            Intent sharingIntent = new Intent(Intent.ACTION_SEND);            sharingIntent.setType("image/png");            sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);            Intent chooserIntent = Intent.createChooser(sharingIntent, null);            chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK                     | Intent.FLAG_ACTIVITY_NEW_TASK);            mNotificationBuilder.addAction(R.drawable.ic_menu_share,                     r.getString(com.android.internal.R.string.share),                     PendingIntent.getActivity(context, 0, chooserIntent,                              PendingIntent.FLAG_CANCEL_CURRENT));            OutputStream out = resolver.openOutputStream(uri);            image.compress(Bitmap.CompressFormat.PNG, 100, out);            out.flush();            out.close();            // update file size in the database            values.clear();            values.put(MediaStore.Images.ImageColumns.SIZE, new File(mImageFilePath).length());            resolver.update(uri, values, null, null);            params[0].imageUri = uri;            params[0].result = 0;        } catch (Exception e) {            // IOException/UnsupportedOperationException may be thrown if external storage is not            // mounted            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            GlobalScreenshot.notifyScreenshotError(params.context, mNotificationManager);        } else {            // Show the final notification to indicate screenshot saved            Resources r = params.context.getResources();            // Create the intent to show the screenshot in gallery            Intent launchIntent = new Intent(Intent.ACTION_VIEW);            launchIntent.setDataAndType(params.imageUri, "image/png");            launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);            mNotificationBuilder                .setContentTitle(r.getString(R.string.screenshot_saved_title))                .setContentText(r.getString(R.string.screenshot_saved_text))                .setContentIntent(PendingIntent.getActivity(params.context, 0, launchIntent, 0))                .setWhen(System.currentTimeMillis())                .setAutoCancel(true);            Notification n = mNotificationBuilder.build();            n.flags &= ~Notification.FLAG_NO_CLEAR;            mNotificationManager.notify(mNotificationId, n);        }        params.finisher.run();    }}/** * 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 int SCREENSHOT_NOTIFICATION_ID = 789;    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 Context mContext;    private WindowManager mWindowManager;    private WindowManager.LayoutParams mWindowLayoutParams;    private NotificationManager mNotificationManager;    private Display mDisplay;    private DisplayMetrics mDisplayMetrics;    private Matrix mDisplayMatrix;    private Bitmap mScreenBitmap;    private View mScreenshotLayout;    private ImageView mBackgroundView;    private ImageView mScreenshotView;    private ImageView mScreenshotFlash;    private AnimatorSet mScreenshotAnimation;    private int mNotificationIconSize;    private float mBgPadding;    private float mBgPaddingScale;    private MediaActionSound mCameraSound;    /**     * @param context everything needs a context :(     */    public GlobalScreenshot(Context context) {        Resources r = context.getResources();        mContext = context;        LayoutInflater layoutInflater = (LayoutInflater)                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);        // Inflate the screenshot layout        mDisplayMatrix = new Matrix();        mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);        mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);        mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);        mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash);        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        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_LAYOUT_IN_SCREEN                    | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,                PixelFormat.TRANSLUCENT);        mWindowLayoutParams.setTitle("ScreenshotAnimation");        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        mNotificationManager =            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);        mDisplay = mWindowManager.getDefaultDisplay();        mDisplayMetrics = new DisplayMetrics();        mDisplay.getRealMetrics(mDisplayMetrics);        // Get the various target sizes        mNotificationIconSize =            r.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);        // Scale has to account for both sides of the bg        mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_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(Runnable finisher) {        SaveImageInBackgroundData data = new SaveImageInBackgroundData();        data.context = mContext;        data.image = mScreenBitmap;        data.iconSize = mNotificationIconSize;        data.finisher = finisher;        new SaveImageInBackgroundTask(mContext, data, mNotificationManager,                SCREENSHOT_NOTIFICATION_ID).execute(data);    }    /**     * @return the current display rotation in degrees     */    private float getDegreesForRotation(int value) {        switch (value) {        case Surface.ROTATION_90:            return 360f - 90f;        case Surface.ROTATION_180:            return 360f - 180f;        case Surface.ROTATION_270:            return 360f - 270f;        }        return 0f;    }    /**     * Takes a screenshot of the current display and shows an animation.     */    void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {        // 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]);        }        // Take the screenshot        mScreenBitmap = Surface.screenshot((int) dims[0], (int) dims[1]);        if (mScreenBitmap == null) {            notifyScreenshotError(mContext, mNotificationManager);            finisher.run();            return;        }        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(degrees);            c.translate(-dims[0] / 2, -dims[1] / 2);            c.drawBitmap(mScreenBitmap, 0, 0, null);            c.setBitmap(null);            mScreenBitmap = ss;        }        // Optimizations        mScreenBitmap.setHasAlpha(false);        mScreenBitmap.prepareToDraw();        // Start the post-screenshot animation        startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,                statusBarVisible, navBarVisible);    }    /**     * Starts the animation after taking the screenshot     */    private void startAnimation(final Runnable finisher, int w, int h, boolean statusBarVisible,            boolean navBarVisible) {        // 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 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);                mWindowManager.removeView(mScreenshotLayout);            }        });        mScreenshotLayout.post(new Runnable() {            @Override            public void run() {                // 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);            }        };        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;    }    static void notifyScreenshotError(Context context, NotificationManager nManager) {        Resources r = context.getResources();        // Clear all existing notification, compose the new notification and show it        Notification n = new Notification.Builder(context)            .setTicker(r.getString(R.string.screenshot_failed_title))            .setContentTitle(r.getString(R.string.screenshot_failed_title))            .setContentText(r.getString(R.string.screenshot_failed_text))            .setSmallIcon(R.drawable.stat_notify_image_error)            .setWhen(System.currentTimeMillis())            .setAutoCancel(true)            .getNotification();        nManager.notify(SCREENSHOT_NOTIFICATION_ID, n);    }

可以从这部分源码中,去寻找解决办法。

其中有一个很重要的方法就是        

mScreenBitmap = Surface.screenshot((int) dims[0], (int) dims[1]);

这个是可以截图的,但是是隐藏的代码,不提供外面调用的。

注意需要在AndroidManifest.xml中加入代码:android:sharedUserId="android.uid.system"  进行后续开发。

先到这里,有时间后续再从这里往下研究。各位也可以yanjiuyxia

本文demo下载地址:http://download.csdn.net/detail/qq_16064871/9420810

4 0