diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index b09bdc045655..1773c056d683 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -18,6 +18,7 @@
package com.android.keyguard;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.TransitionDrawable;
@@ -31,6 +32,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -68,6 +70,8 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
+import java.io.File;
+
/**
* Manages creating, showing, hiding and resetting the keyguard. Calls back
* via {@link KeyguardViewMediator.ViewMediatorCallback} to poke
@@ -78,6 +82,8 @@ public class KeyguardViewManager {
private final static boolean DEBUG = KeyguardViewMediator.DEBUG;
private static String TAG = "KeyguardViewManager";
public final static String IS_SWITCHING_USER = "is_switching_user";
+ private static final String INTENT_LOCKSCREEN_WALLPAPER_CHANGED = "lockscreen_changed";
+ private static final String LOCKSCREEN_IMAGE_FILE = "/lockwallpaper.sav";
// Delay dismissing keyguard to allow animations to complete.
private static final int HIDE_KEYGUARD_DELAY = 500;
@@ -99,7 +105,9 @@ public class KeyguardViewManager {
private ViewManagerHost mKeyguardHost;
private KeyguardHostView mKeyguardView;
+ private WallpaperObserver mReceiver;
+ private boolean mBackgroundInitialized;
private boolean mScreenOn = false;
private LockPatternUtils mLockPatternUtils;
@@ -109,9 +117,37 @@ public class KeyguardViewManager {
private boolean mLockscreenNotifications = false;
private Bitmap mBlurredImage = null;
+ private Bitmap mLockscreenBackground;
private boolean mRotated = false;
private int mLastRotation = 0;
+ class WallpaperObserver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(INTENT_LOCKSCREEN_WALLPAPER_CHANGED)) {
+ customLockscreen();
+ }
+ }
+ }
+
+ private void customLockscreen() {
+ mLockscreenBackground = null;
+ String path = mContext.getExternalCacheDir().getAbsolutePath();
+ path = path.replace("com.android.keyguard", "com.android.wallpapercropper");
+ File file = new File(path + LOCKSCREEN_IMAGE_FILE);
+ if (file.exists()) {
+ mLockscreenBackground = BitmapFactory.decodeFile(file.getAbsolutePath());
+ }
+ }
+
+ private void registerWallpaperReceiver() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(INTENT_LOCKSCREEN_WALLPAPER_CHANGED);
+ mReceiver = new WallpaperObserver();
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
private KeyguardUpdateMonitorCallback mBackgroundChanger = new KeyguardUpdateMonitorCallback() {
@Override
public void onSetBackground(Bitmap bmp) {
@@ -283,6 +319,22 @@ public int getOpacity() {
public ViewManagerHost(Context context) {
super(context);
+ registerWallpaperReceiver();
+ customLockscreen();
+
+ if (mLockscreenBackground == null) {
+ initBackground();
+ } else {
+ Drawable customLockscreen = new BitmapDrawable(mContext.getResources(),
+ mLockscreenBackground);
+ setBackground(customLockscreen);
+ mBackgroundInitialized = false;
+ }
+
+ }
+
+ public void initBackground() {
+ mBackgroundInitialized = true;
setBackground(mBackgroundDrawable);
}
@@ -317,6 +369,7 @@ public void drawToCanvas(Canvas canvas, Drawable drawable) {
}
public void setCustomBackground(Drawable d) {
+ if (!isLaidOut()) return;
if (!ActivityManager.isHighEndGfx() || !mScreenOn) {
mCustomBackground = d;
if (d != null) {
@@ -498,8 +551,8 @@ private void maybeCreateKeyguardLocked(int rotationAngles, boolean force,
mKeyguardHost.restoreHierarchyState(mStateContainer);
- if (mBlurredImage != null) {
- setCustomBackground(mBlurredImage);
+ if (mBlurredImage != null || mLockscreenBackground != null) {
+ setCustomBackground(mBlurredImage == null ? mLockscreenBackground : mBlurredImage);
}
}
@@ -724,6 +777,7 @@ public synchronized void hide() {
}
if (mKeyguardHost != null) {
+ if (!mBackgroundInitialized) mKeyguardHost.initBackground();
mKeyguardHost.setVisibility(View.GONE);
// We really only want to preserve keyguard state for configuration changes. Hence
diff --git a/packages/WallpaperCropper/AndroidManifest.xml b/packages/WallpaperCropper/AndroidManifest.xml
index 27755bd2c7cc..9fbc23d514c5 100644
--- a/packages/WallpaperCropper/AndroidManifest.xml
+++ b/packages/WallpaperCropper/AndroidManifest.xml
@@ -2,6 +2,9 @@
package="com.android.wallpapercropper" >
+
+
+
+
+
+
+
+
+
diff --git a/packages/WallpaperCropper/res/layout/actionbar_set_lockscreen.xml b/packages/WallpaperCropper/res/layout/actionbar_set_lockscreen.xml
new file mode 100644
index 000000000000..f7b9edc61e3b
--- /dev/null
+++ b/packages/WallpaperCropper/res/layout/actionbar_set_lockscreen.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
diff --git a/packages/WallpaperCropper/res/layout/blur_dialog.xml b/packages/WallpaperCropper/res/layout/blur_dialog.xml
new file mode 100644
index 000000000000..00b223ba4632
--- /dev/null
+++ b/packages/WallpaperCropper/res/layout/blur_dialog.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
diff --git a/packages/WallpaperCropper/res/layout/lockscreen_main.xml b/packages/WallpaperCropper/res/layout/lockscreen_main.xml
new file mode 100644
index 000000000000..1aa3db6f9065
--- /dev/null
+++ b/packages/WallpaperCropper/res/layout/lockscreen_main.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/WallpaperCropper/res/mipmap-hdpi/ic_lockscreen_wallpaper.png b/packages/WallpaperCropper/res/mipmap-hdpi/ic_lockscreen_wallpaper.png
new file mode 100644
index 000000000000..affee851d777
Binary files /dev/null and b/packages/WallpaperCropper/res/mipmap-hdpi/ic_lockscreen_wallpaper.png differ
diff --git a/packages/WallpaperCropper/res/mipmap-mdpi/ic_lockscreen_wallpaper.png b/packages/WallpaperCropper/res/mipmap-mdpi/ic_lockscreen_wallpaper.png
new file mode 100644
index 000000000000..cb4443bdb9cf
Binary files /dev/null and b/packages/WallpaperCropper/res/mipmap-mdpi/ic_lockscreen_wallpaper.png differ
diff --git a/packages/WallpaperCropper/res/mipmap-xhdpi/ic_lockscreen_wallpaper.png b/packages/WallpaperCropper/res/mipmap-xhdpi/ic_lockscreen_wallpaper.png
new file mode 100644
index 000000000000..60f8dceec7d8
Binary files /dev/null and b/packages/WallpaperCropper/res/mipmap-xhdpi/ic_lockscreen_wallpaper.png differ
diff --git a/packages/WallpaperCropper/res/mipmap-xxhdpi/ic_lockscreen_wallpaper.png b/packages/WallpaperCropper/res/mipmap-xxhdpi/ic_lockscreen_wallpaper.png
new file mode 100644
index 000000000000..023fb5886938
Binary files /dev/null and b/packages/WallpaperCropper/res/mipmap-xxhdpi/ic_lockscreen_wallpaper.png differ
diff --git a/packages/WallpaperCropper/res/values/pa_strings.xml b/packages/WallpaperCropper/res/values/pa_strings.xml
new file mode 100644
index 000000000000..326c9682ba30
--- /dev/null
+++ b/packages/WallpaperCropper/res/values/pa_strings.xml
@@ -0,0 +1,25 @@
+
+
+
+ Lock screen
+ Reset
+ Browse
+ Blur
+ Blur radius
+ Set lockscreen image
+ Lockscreen image updated
+ Lockscreen image reset
+
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/LockscreenWallpaper.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/LockscreenWallpaper.java
new file mode 100644
index 000000000000..fadaf09d57e4
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/LockscreenWallpaper.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2014 ParanoidAndroid 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.wallpapercropper;
+
+import android.app.Activity;
+import android.app.ActionBar;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Dialog;
+import android.app.WallpaperManager;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Images;
+import android.provider.Settings.SettingNotFoundException;
+import android.provider.Settings;
+import android.renderscript.Allocation;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.ScriptIntrinsicBlur;
+import android.util.Log;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class LockscreenWallpaper extends Activity {
+ private static final String TAG = "CUSTOM_LOCKSCREEN";
+
+ private static final String INTENT_LOCKSCREEN_WALLPAPER_CHANGED = "lockscreen_changed";
+ private static final int REQUEST_CODE_BG_WALLPAPER = 1024;
+ private static final int REQUEST_CODE_CROP_WALLPAPER = 1025;
+ private static final int DEFAULT_BLUR = 16;
+
+ private SeekBar sBar;
+ private Context mContext;
+ private Dialog mDialog;
+ private File mWallpaperTemporary, mSavedLockscreen;
+ private ActionBar actionBar;
+ private ViewGroup mRoot;
+ private ImageView mBackground, mPreview;
+ private Drawable mBlurredImage;
+ private boolean mBlurLevelUpdated;
+ private String mPath;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (!enableRotation()) {
+ setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT);
+ }
+
+ mContext = getBaseContext();
+ setContentView(R.layout.lockscreen_main);
+
+ View mRoot = findViewById(R.id.lockscreen_root);
+ View reset = findViewById(R.id.lockscreen_reset);
+ View select = findViewById(R.id.lockscreen_select);
+ View blur = findViewById(R.id.lockscreen_blur);
+
+ mWallpaperTemporary = new File(mContext.getExternalCacheDir() + "/lockwallpaper.tmp");
+ mSavedLockscreen = new File(mContext.getExternalCacheDir() + "/lockwallpaper.sav");
+ mBackground = (ImageView) findViewById(R.id.picker_background);
+ mPreview = (ImageView) findViewById(R.id.lockscreen_preview);
+ Drawable image = getCurrentWallpaper();
+
+ if (mSavedLockscreen.exists()) {
+ mPreview.setBackground(image);
+ } else {
+ mBackground.setBackground(image);
+ resizeLayout(image);
+ }
+
+ LayoutInflater inflater = (LayoutInflater)this.getSystemService(LAYOUT_INFLATER_SERVICE);
+ View dialogLayout = inflater.inflate(R.layout.blur_dialog,
+ (ViewGroup)findViewById(R.id.blur_dialog));
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.blur_radius)
+ .setView(dialogLayout);
+
+ mDialog = builder.create();
+
+ sBar = (SeekBar) dialogLayout.findViewById(R.id.blur_seekbar);
+ sBar.setOnSeekBarChangeListener(mSeekBarListener);
+
+ actionBar = getActionBar();
+ actionBar.setCustomView(R.layout.actionbar_set_lockscreen);
+ actionBar.getCustomView().setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.LOCKSCREEN_SEE_THROUGH, 0);
+
+ if (mBlurredImage == null) {
+ // copy temp image to save file
+ try {
+ moveFile(mWallpaperTemporary, mSavedLockscreen);
+ } catch (IOException e){
+ Log.e(TAG, "failed to move file");
+ }
+ } else {
+ // write directy to save file
+ try {
+ Bitmap bmp = ((BitmapDrawable)mBlurredImage).getBitmap();
+ FileOutputStream fileOut = new FileOutputStream(mSavedLockscreen);
+ bmp.compress(Bitmap.CompressFormat.PNG, 100, fileOut);
+ fileOut.flush();
+ fileOut.close();
+ } catch (FileNotFoundException ex) {
+ Log.e(TAG, "file not found: " + ex.toString());
+ } catch (IOException e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ Intent intent = new Intent();
+ intent.setAction(INTENT_LOCKSCREEN_WALLPAPER_CHANGED);
+ sendBroadcast(intent);
+ finish();
+ Toast.makeText(mContext, R.string.lockscreen_image_set,
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+ reset.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ reset();
+ mWallpaperTemporary.delete();
+
+ if (mSavedLockscreen.delete()) {
+ Intent intent = new Intent();
+ intent.setAction(INTENT_LOCKSCREEN_WALLPAPER_CHANGED);
+ sendBroadcast(intent);
+ Toast.makeText(mContext, R.string.lockscreen_image_reset,
+ Toast.LENGTH_SHORT).show();
+ }
+ mPreview.setBackground(null);
+ mBackground.setBackground(null);
+ Drawable image = getCurrentWallpaper();
+ mBackground.setBackground(image);
+ resizeLayout(image);
+ actionBar.hide();
+ }
+ });
+ select.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ pickImage();
+ }
+ });
+ blur.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (!mWallpaperTemporary.exists()) {
+ cropImage(getCurrentWallpaper());
+ } else {
+ loadBlurDialog();
+ }
+ actionBar.show();
+ }
+ });
+ actionBar.hide();
+ }
+
+ public boolean enableRotation() {
+ return getResources().getBoolean(R.bool.allow_rotation);
+ }
+
+ private void loadBlurDialog() {
+ mDialog.show();
+ String title = getResources().getString(R.string.blur_radius);
+ mDialog.setTitle(title + ": " + Integer.toString(sBar.getProgress()));
+ mBlurredImage = blurBitmap(getPreview(), sBar.getProgress());
+ mPreview.setBackground(mBlurredImage);
+ }
+
+ private void resizeLayout(Drawable image) {
+ LinearLayout.LayoutParams params =
+ (LinearLayout.LayoutParams) mBackground.getLayoutParams();
+ params.width = image.getIntrinsicWidth();
+ params.height = image.getIntrinsicHeight();
+ mBackground.setLayoutParams(params);
+ }
+
+ private void pickImage() {
+ final Intent intent = new Intent(Intent.ACTION_PICK,
+ android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+ intent.setType("image/*");
+ intent.putExtra("crop", "true");
+ intent.putExtra("scale", true);
+ intent.putExtra("scaleUpIfNeeded", false);
+ intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
+
+ final Display display = getWindowManager().getDefaultDisplay();
+
+ boolean isPortrait = getResources().getConfiguration().orientation ==
+ Configuration.ORIENTATION_PORTRAIT;
+
+ Point size = new Point();
+ display.getSize(size);
+
+ intent.putExtra("aspectX", isPortrait ? size.x : size.y);
+ intent.putExtra("aspectY", isPortrait ? size.y : size.x);
+
+ try {
+ mWallpaperTemporary.deleteOnExit();
+ mWallpaperTemporary.createNewFile();
+ mWallpaperTemporary.setWritable(true, false);
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mWallpaperTemporary));
+ intent.putExtra("return-data", false);
+ startActivityForResult(intent, REQUEST_CODE_BG_WALLPAPER);
+ } catch (IOException e) {
+ // Do nothing
+ } catch (ActivityNotFoundException e) {
+ // Do nothing
+ }
+ }
+
+ private void cropImage(Drawable image) {
+ Bitmap bmp = ((BitmapDrawable)image).getBitmap();
+ try {
+ Intent cropIntent = new Intent("com.android.camera.action.CROP");
+ mPath = Images.Media.insertImage(mContext.getContentResolver(), bmp, null, null);
+ cropIntent.setDataAndType(Uri.parse(mPath), "image/*");
+ cropIntent.putExtra("crop", "true");
+ cropIntent.putExtra("scale", true);
+ cropIntent.putExtra("scaleUpIfNeeded", false);
+
+ final Display display = getWindowManager().getDefaultDisplay();
+
+ boolean isPortrait = getResources().getConfiguration().orientation ==
+ Configuration.ORIENTATION_PORTRAIT;
+
+ Point size = new Point();
+ display.getSize(size);
+
+ cropIntent.putExtra("aspectX", isPortrait ? size.x : size.y);
+ cropIntent.putExtra("aspectY", isPortrait ? size.y : size.x);
+ cropIntent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
+ cropIntent.putExtra("return-data", false);
+
+ cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mWallpaperTemporary));
+
+ startActivityForResult(cropIntent, REQUEST_CODE_CROP_WALLPAPER);
+ }
+ catch (ActivityNotFoundException e) {
+ // activity not found
+ }
+ }
+
+ private Drawable blurBitmap(Drawable image, int radius) {
+ Bitmap bmp = scaleToFitWidth(((BitmapDrawable)image).getBitmap());
+ Bitmap out = Bitmap.createBitmap(bmp);
+
+ RenderScript rs = RenderScript.create(mContext);
+
+ Allocation input = Allocation.createFromBitmap(
+ rs, bmp, MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
+ Allocation output = Allocation.createTyped(rs, input.getType());
+
+ ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
+ script.setInput(input);
+ script.setRadius(radius < 1 ? 1 : radius);
+ script.forEach(output);
+
+ output.copyTo(out);
+
+ rs.destroy();
+
+ Drawable blurred = new BitmapDrawable(getResources(), out);
+
+ return blurred;
+ }
+
+ private Drawable getCurrentWallpaper() {
+ Drawable wallpaperDrawable = null;
+ if (mSavedLockscreen.exists()) {
+ Bitmap bmp = BitmapFactory.decodeFile(mSavedLockscreen.getAbsolutePath());
+ wallpaperDrawable = new BitmapDrawable(getResources(), bmp);
+ } else {
+ WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
+ wallpaperDrawable = wallpaperManager.getDrawable();
+ }
+ return wallpaperDrawable;
+ }
+
+ private Drawable getPreview() {
+ if (!mWallpaperTemporary.exists()) return getCurrentWallpaper();
+
+ Bitmap bmp = BitmapFactory.decodeFile(mWallpaperTemporary.getAbsolutePath());
+ Drawable bg = new BitmapDrawable(getResources(), bmp);
+ return bg == null ? getCurrentWallpaper() : bg;
+ }
+
+ private OnSeekBarChangeListener mSeekBarListener = new OnSeekBarChangeListener() {
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ mBlurredImage = blurBitmap(getPreview(), seekBar.getProgress());
+ if (mWallpaperTemporary.exists()) {
+ mPreview.setBackground(mBlurredImage);
+ } else {
+ mPreview.setBackground(null);
+ mBackground.setBackground(mBlurredImage);
+ resizeLayout(mBlurredImage);
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seekBark, int progress, boolean fromUser) {
+ mBlurLevelUpdated = true;
+ String title = getResources().getString(R.string.blur_radius);
+ mDialog.setTitle(title + ": " + Integer.toString(progress));
+ }
+ };
+
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent imageReturnedIntent) {
+ if (requestCode == REQUEST_CODE_BG_WALLPAPER) {
+ if (resultCode == Activity.RESULT_OK) {
+ mPreview.setBackground(getPreview());
+ actionBar.show();
+ reset();
+ }
+ } else if (requestCode == REQUEST_CODE_CROP_WALLPAPER) {
+ if (resultCode == Activity.RESULT_OK) {
+ mContext.getContentResolver().delete(Uri.parse(mPath), null, null);
+ Bitmap bmp = BitmapFactory.decodeFile(mWallpaperTemporary.getAbsolutePath());
+ mPreview.setBackground(new BitmapDrawable(getResources(), bmp));
+ loadBlurDialog();
+ }
+ }
+ }
+
+ public void reset() {
+ mBlurredImage = null;
+ mBlurLevelUpdated = false;
+ if (sBar != null) sBar.setProgress(DEFAULT_BLUR);
+ }
+
+ public void moveFile(File src, File dst) throws IOException {
+ InputStream in = new FileInputStream(src);
+ OutputStream out = new FileOutputStream(dst);
+
+ // Transfer bytes from in to out
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ in.close();
+ out.close();
+ }
+
+ static public Bitmap scaleToFitWidth(Bitmap b) {
+ int scaledWidth = (int)Math.round(b.getWidth() / 4) * 4;
+ float factor = b.getWidth() / scaledWidth;
+ return Bitmap.createScaledBitmap(b, scaledWidth, (int) (b.getHeight() * factor), false);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ reset();
+ }
+}