/** 获得功能表底部背景图片:当拖动图标至桌面时的背景效果图 */
 public MImage getMoveToDeskBg() {
   if (isVertical()) {
     if (mMoveToDesk_v == null) {
       try {
         mMoveToDesk_v =
             generateMImage(R.drawable.appfunc_movetodesk, getScreenWidth(), getRealNum(85), 0);
       } catch (OutOfMemoryError e) {
         e.printStackTrace();
         OutOfMemoryHandler.handle();
       }
     }
     return mMoveToDesk_v;
   } else {
     if (mMoveToDesk_h == null) {
       try {
         mMoveToDesk_h =
             generateMImage(
                 R.drawable.appfunc_movetodesk, getScreenHeight(), getRealNum(85), -90.0f);
       } catch (OutOfMemoryError e) {
         e.printStackTrace();
         OutOfMemoryHandler.handle();
       }
     }
     return mMoveToDesk_h;
   }
 }
 /** 获得功能表底部背景图片: 底层为BitmapDrawable格式 */
 public MImage getBottomBg() {
   if (isVertical()) {
     if (mBottomBg_v == null) {
       try {
         mBottomBg_v =
             generateMImage(R.drawable.shorcut_slaver, getScreenWidth(), getRealNum(85), 0);
       } catch (OutOfMemoryError e) {
         e.printStackTrace();
         OutOfMemoryHandler.handle();
       }
     }
     return mBottomBg_v;
   } else {
     if (mBottomBg_h == null) {
       try {
         mBottomBg_h =
             generateMImage(R.drawable.shorcut_slaver, getScreenHeight(), getRealNum(85), -90.0f);
       } catch (OutOfMemoryError e) {
         e.printStackTrace();
         OutOfMemoryHandler.handle();
       }
     }
     return mBottomBg_h;
   }
 }
 /**
  * 获取关闭高光图标的副本
  *
  * @return
  */
 public BitmapDrawable getColseLightIconCopy() {
   try {
     if (mCloseLightIcon == null) {
       if (mThemeController == null) {
         mThemeController = AppFuncFrame.getThemeController();
       }
       BitmapDrawable origImg =
           (BitmapDrawable)
               mThemeController.getDrawable(
                   mThemeController.getThemeBean().mAppIconBean.mKillAppLight);
       if (origImg != null) {
         Bitmap copy = origImg.getBitmap().copy(Bitmap.Config.ARGB_8888, true);
         if (copy != null) {
           mCloseLightIcon = new BitmapDrawable(mContext.getResources(), copy);
         }
       }
     }
   } catch (OutOfMemoryError e) {
     e.printStackTrace();
     OutOfMemoryHandler.handle();
   } catch (Exception e) {
     e.printStackTrace();
   }
   return mCloseLightIcon;
 }
 /**
  * 获取编辑文件夹高光图标的副本
  *
  * @return
  */
 public BitmapDrawable getEditLightIconCopy() {
   try {
     if (mEditLightIcon == null) {
       // BitmapDrawable origImg = (BitmapDrawable) mActivity
       // .getResources().getDrawable(
       // R.drawable.eidt_folder_light);
       if (mThemeController == null) {
         mThemeController = AppFuncFrame.getThemeController();
       }
       BitmapDrawable origImg =
           (BitmapDrawable)
               mThemeController.getDrawable(
                   mThemeController.getThemeBean().mAppIconBean.mEditHighlightFolder);
       if (origImg != null) {
         Bitmap copy = origImg.getBitmap().copy(Bitmap.Config.ARGB_8888, true);
         if (copy != null) {
           mEditLightIcon = new BitmapDrawable(mContext.getResources(), copy);
         }
       }
     }
   } catch (OutOfMemoryError e) {
     e.printStackTrace();
     OutOfMemoryHandler.handle();
   } catch (Exception e) {
     e.printStackTrace();
   }
   return mEditLightIcon;
 }
 /**
  * 获取卸载图标的副本
  *
  * @return
  */
 public BitmapDrawable getKillIconCopy() {
   try {
     if (mKillImg == null) {
       // BitmapDrawable origImg = (BitmapDrawable) mActivity
       // .getResources().getDrawable(R.drawable.kill);
       if (mThemeController == null) {
         mThemeController = AppFuncFrame.getThemeController();
       }
       BitmapDrawable origImg =
           (BitmapDrawable)
               mThemeController.getDrawable(
                   mThemeController.getThemeBean().mAppIconBean.mDeletApp);
       if (origImg != null) {
         Bitmap copy = origImg.getBitmap().copy(Bitmap.Config.ARGB_8888, true);
         if (copy != null) {
           mKillImg = new BitmapDrawable(mContext.getResources(), copy);
         }
       }
     }
   } catch (OutOfMemoryError e) {
     e.printStackTrace();
     OutOfMemoryHandler.handle();
   } catch (Exception e) {
     e.printStackTrace();
   }
   return mKillImg;
 }
 /**
  * 获得格式为Drawable的图片
  *
  * @param drawableId
  * @return
  */
 public Drawable getDrawable(int drawableId) {
   Drawable img = null;
   try {
     if (mPublicResources.containsKey(drawableId)) {
       // 与主题无关的资源不保存在主题资源管理器中
       img = getDrawableFromMainPkg(drawableId);
     } else {
       img = mPicManager.getViewDrawable(drawableId);
     }
   } catch (OutOfMemoryError e) {
     Log.d("XViewFrame", "Hoops! Out of Memeory");
     e.printStackTrace();
     OutOfMemoryHandler.handle();
   }
   return img;
 }
 private Bitmap createNoCropBitmap() {
   Bitmap bitmap = mBitmap;
   try {
     if (null != bitmap) {
       int bmpW = bitmap.getWidth();
       int bmpH = bitmap.getHeight();
       float wScale = (float) mOutputX / (float) bmpW;
       float hScale = (float) mOutputY / (float) bmpH;
       float scale = wScale < hScale ? wScale : hScale;
       boolean needScale = scale < 1;
       boolean needYFit = false;
       if (scale < 1) {
         needYFit = (int) (bmpH * scale) < mOutputY - 1; // 由于缩放误差1个单位
       } else {
         needYFit = bmpH < mOutputY;
       }
       boolean needXFit = false; // for dock
       if (scale < 1) {
         needXFit = (int) (bmpW * scale) < mOutputX - 1; // 由于缩放误差1个单位
       } else {
         needXFit = bmpW < mOutputX;
       }
       if (needScale) {
         Bitmap tempbitmap =
             BitmapUtility.createScaledBitmap(bitmap, (int) (bmpW * scale), (int) (bmpH * scale));
         bitmap.recycle();
         bitmap = tempbitmap;
       }
       if (needYFit || needXFit) {
         Bitmap tempbitmap = BitmapUtility.createBitmap(bitmap, mOutputX, mOutputY);
         bitmap.recycle();
         bitmap = tempbitmap;
       }
     }
   } catch (OutOfMemoryError e) {
     OutOfMemoryHandler.handle();
     e.printStackTrace();
     bitmap = null;
   } catch (Exception e) {
     e.printStackTrace();
     bitmap = null;
   }
   return bitmap;
 }
  private boolean decodeBitmapStreamSafe(Uri target) {
    String path = uriToFilePath(target, this);
    int degree = 0;
    if (path != null) {
      degree = readBitmapDegree(path);
    }

    InputStream is = null;

    boolean bool = true;
    int scale = 1;
    Options opt = new Options();
    while (bool) {
      try {
        is = mContentResolver.openInputStream(target);
        opt.inSampleSize = scale;
        mBitmap = null;
        mBitmap = BitmapFactory.decodeStream(is, null, opt);
        mBitmap = postRotateToBitmap(degree, mBitmap);
        mHasApha = mBitmap.hasAlpha();
        bool = false;

        return true;
      } catch (OutOfMemoryError e) {
        // 如果解碼大圖片,出现爆内存,则每次缩放一半
        OutOfMemoryHandler.handle();
        scale *= 2;
        if (scale > (1 << 10)) {
          // 防止异常死循环
          return false;
        }
      } catch (Throwable e) {
        // TODO: handle Throwable
        bool = false;

        return false;
      }
    }
    return false;
  }
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    mContentResolver = getContentResolver();

    requestWindowFeature(Window.FEATURE_NO_TITLE);

    // MenuHelper.showStorageToast(this);

    Intent intent = getIntent();
    Bundle extras = intent.getExtras();

    if (extras != null) {
      // if (extras.getString("circleCrop") != null) {
      // mCircleCrop = true;
      // mAspectX = 1;
      // mAspectY = 1;
      // }
      mSaveUri = (Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT);
      if (mSaveUri != null) {
        String outputFormatString = extras.getString("outputFormat");
        if (outputFormatString != null) {
          mOutputFormat = Bitmap.CompressFormat.valueOf(outputFormatString);
        }
      } else {
        mSetWallpaper = extras.getBoolean("setWallpaper");
      }
      mBitmap = (Bitmap) extras.getParcelable("data");
      mAspectX = extras.getInt("aspectX");
      mAspectY = extras.getInt("aspectY");
      mOutputX = extras.getInt("outputX");
      mOutputY = extras.getInt("outputY");
      mScale = extras.getBoolean("scale", false);
      mScaleUp = extras.getBoolean("scaleUpIfNeeded", false);
      // mDoFaceDetection = extras.containsKey("noFaceDetection")
      // ? !extras.getBoolean("noFaceDetection")
      // : true;

      android.content.res.Resources resources = getResources();
      int id = extras.getInt("arrowHorizontal", -1);
      if (id != -1) {
        mResizeDrawableWidth = resources.getDrawable(id);
      }
      id = extras.getInt("arrowVertical", -1);
      if (id != -1) {
        mResizeDrawableHeight = resources.getDrawable(id);
      }
      // id = extras.getInt("arrowDiagonal", -1);
      // if(id != -1){
      // mResizeDrawableDiagonal = resources.getDrawable(id);
      // }
    }

    if (mBitmap == null) {
      Uri target = intent.getData();
      try {
        decodeBitmapStreamSafe(target);
      } catch (OutOfMemoryError e) {
        OutOfMemoryHandler.handle();
      } catch (Throwable e) {
        e.printStackTrace();
      }
      // TODO
      // if (mImage != null) {
      // // Don't read in really large bitmaps. Use the (big) thumbnail
      // // instead.
      // // TODO when saving the resulting bitmap use the
      // // decode/crop/encode api so we don't lose any resolution.
      // mBitmap = mImage.thumbBitmap(IImage.ROTATE_AS_NEEDED);
      // }
    }

    if (mBitmap == null) {
      setResult(RESULT_CANCELED);
      finish();
      return;
    }

    // Make UI fullscreen.
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView(R.layout.cropimage);

    mImageView = (CropImageView) findViewById(R.id.image);
    findViewById(R.id.discard)
        .setOnClickListener(
            new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                setResult(RESULT_CANCELED);
                finish();
              }
            });

    findViewById(R.id.crop)
        .setOnClickListener(
            new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                onSaveClicked();
              }
            });

    final Button btn = (Button) findViewById(R.id.no_crop);
    btn.setOnClickListener(
        new View.OnClickListener() {
          @Override
          public void onClick(View v) {
            // if (mNeedCrop)
            // {
            // mImageView.setImageBitmapResetBase(mBitmap, true);
            // mImageView.remove(mCrop);
            // mCrop = null;
            //
            // btn.setText(R.string.crop_text);
            // }
            // else
            // {
            // makeDefault();
            // mImageView.requestLayout();
            // mCrop = mImageView.mHighlightViews.get(0);
            // mCrop.setFocus(true);
            //
            // btn.setText(R.string.no_crop_text);
            // }
            // mNeedCrop = !mNeedCrop;
            mNeedCrop = false;
            onSaveClicked();
          }
        });

    // startFaceDetection();
    mImageView.setImageBitmapResetBase(mBitmap, true);
    makeDefault();
    mCrop = mImageView.mHighlightViews.get(0);
    mCrop.setFocus(true);
  }
  private void onSaveClicked() {
    if (!mNeedCrop) {
      Bitmap nocropBitmap = createNoCropBitmap();
      mImageView.clear();
      if (nocropBitmap != mBitmap) {
        mBitmap.recycle();
        mBitmap = null;
      }
      if (null != nocropBitmap) {
        // Return the cropped image directly or save it to the specified
        // URI.
        Bundle myExtras = getIntent().getExtras();
        if (myExtras != null
            && (myExtras.getParcelable("data") != null || myExtras.getBoolean("return-data"))) {
          Bundle extras = new Bundle();
          extras.putParcelable("data", nocropBitmap);
          setResult(
              RESULT_OK,
              (new Intent()).setAction(ICustomAction.ACTION_INLINE_DATA).putExtras(extras));
          finish();
        } else {
          final Bitmap b = nocropBitmap;
          final int msdId = mSetWallpaper ? R.string.wallpaper : R.string.savingImage;
          Util.startBackgroundJob(
              this,
              null,
              getResources().getString(msdId),
              new Runnable() {
                @Override
                public void run() {
                  saveOutput(b);
                }
              },
              mHandler);
        }
      } else {
        setResult(RESULT_CANCELED);
        finish();
      }
      return;
    }
    // TODO this code needs to change to use the decode/crop/encode single
    // step api so that we don't require that the whole (possibly large)
    // bitmap doesn't have to be read into memory
    if (mCrop == null) {
      return;
    }

    if (mSaving) {
      return;
    }
    mSaving = true;

    Bitmap croppedImage = null;
    Bitmap.Config bmpConfig = mHasApha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.ARGB_8888;

    // If the output is required to a specific size, create an new image
    // with the cropped image in the center and the extra space filled.
    if (mOutputX != 0 && mOutputY != 0 && !mScale) {
      // Don't scale the image but instead fill it so it's the
      // required dimension
      try {
        croppedImage = Bitmap.createBitmap(mOutputX, mOutputY, bmpConfig);
      } catch (OutOfMemoryError e) {
        // 创建失败
        e.printStackTrace();
        OutOfMemoryHandler.handle();
        Toast.makeText(this, getString(R.string.err_out_of_memory), Toast.LENGTH_SHORT);
        // Release bitmap memory as soon as possible
        mImageView.clear();
        mBitmap.recycle();
        mBitmap = null;

        setResult(RESULT_CANCELED);
        finish();
        return;
      }

      Canvas canvas = new Canvas(croppedImage);
      Rect srcRect = mCrop.getCropRect();
      Rect dstRect = new Rect(0, 0, mOutputX, mOutputY);

      int dx = (srcRect.width() - dstRect.width()) / 2;
      int dy = (srcRect.height() - dstRect.height()) / 2;

      // If the srcRect is too big, use the center part of it.
      srcRect.inset(Math.max(0, dx), Math.max(0, dy));

      // If the dstRect is too big, use the center part of it.
      dstRect.inset(Math.max(0, -dx), Math.max(0, -dy));

      // Draw the cropped bitmap in the center
      canvas.drawBitmap(mBitmap, srcRect, dstRect, null);

      // Release bitmap memory as soon as possible
      mImageView.clear();
      mBitmap.recycle();
    } else {
      Rect r = mCrop.getCropRect();

      // int width = r.width();
      // int height = r.height();

      // If we are circle cropping, we want alpha channel, which is the
      // third param here.
      try {
        croppedImage = Bitmap.createBitmap(mOutputX, mOutputY, bmpConfig);
      } catch (OutOfMemoryError e) {
        e.printStackTrace();
        OutOfMemoryHandler.handle();
        // 创建失败
        // Toast.makeText(this, getString(R.string.err_out_of_memory),
        // Toast.LENGTH_SHORT).show();
        // Release bitmap memory as soon as possible
        mImageView.clear();
        mBitmap.recycle();

        setResult(RESULT_CANCELED);
        finish();
        return;
      }

      Canvas canvas = new Canvas(croppedImage);
      canvas.setDrawFilter(
          new PaintFlagsDrawFilter(
              0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG)); // 在有缩放的情况下需要提高绘图质量
      Rect dstRect = new Rect(0, 0, mOutputX, mOutputY);
      canvas.drawBitmap(mBitmap, r, dstRect, null);

      // Release bitmap memory as soon as possible
      mImageView.clear();
      mBitmap.recycle();

      // if (mCircleCrop) {
      // // OK, so what's all this about?
      // // Bitmaps are inherently rectangular but we want to return
      // // something that's basically a circle. So we fill in the
      // // area around the circle with alpha. Note the all important
      // // PortDuff.Mode.CLEAR.
      // Canvas c = new Canvas(croppedImage);
      // Path p = new Path();
      // p.addCircle(width / 2F, height / 2F, width / 2F,
      // Path.Direction.CW);
      // c.clipPath(p, Region.Op.DIFFERENCE);
      // c.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
      // }

      // If the required dimension is specified, scale the image.
      // if (mOutputX != 0 && mOutputY != 0 && mScale) {
      // croppedImage = Util.transform(new Matrix(), croppedImage,
      // mOutputX, mOutputY, mScaleUp, Util.RECYCLE_INPUT);
      // }
    }

    mImageView.setImageBitmapResetBase(croppedImage, true);
    mImageView.center(true, true);
    mImageView.mHighlightViews.clear();

    // Return the cropped image directly or save it to the specified URI.
    Bundle myExtras = getIntent().getExtras();
    if (myExtras != null
        && (myExtras.getParcelable("data") != null || myExtras.getBoolean("return-data"))) {
      Bundle extras = new Bundle();
      extras.putParcelable("data", croppedImage);
      setResult(
          RESULT_OK, (new Intent()).setAction(ICustomAction.ACTION_INLINE_DATA).putExtras(extras));
      finish();
    } else {
      final Bitmap b = croppedImage;
      final int msdId = mSetWallpaper ? R.string.wallpaper : R.string.savingImage;
      Util.startBackgroundJob(
          this,
          null,
          getResources().getString(msdId),
          new Runnable() {
            @Override
            public void run() {
              saveOutput(b);
            }
          },
          mHandler);
    }
  }