Fix crash in built-in wallpaper cropper

Also, sync to latest version of WallpaperCropActivity

Bug: 10950237
This commit is contained in:
Michael Jurka
2013-10-07 17:03:30 -07:00
parent 619fc89aa1
commit e72aa7f0a6
6 changed files with 182 additions and 54 deletions

View File

@@ -19,7 +19,7 @@
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/wallpaper_cropper"
android:id="@+id/wallpaper_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.android.wallpapercropper.CropView

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 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.
-->
<resources>
<bool name="allow_rotation">true</bool>
</resources>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 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.
-->
<resources>
<bool name="allow_rotation">false</bool>
</resources>

View File

@@ -22,8 +22,8 @@ import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ViewConfiguration;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -44,6 +44,7 @@ public class CropView extends TiledImageView implements OnScaleGestureListener {
public interface TouchCallback {
void onTouchDown();
void onTap();
void onTouchUp();
}
public CropView(Context context) {
@@ -140,12 +141,12 @@ public class CropView extends TiledImageView implements OnScaleGestureListener {
public void onScaleEnd(ScaleGestureDetector detector) {
}
public void moveToUpperLeft() {
public void moveToLeft() {
if (getWidth() == 0 || getHeight() == 0) {
final ViewTreeObserver observer = getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
moveToUpperLeft();
moveToLeft();
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
@@ -154,7 +155,6 @@ public class CropView extends TiledImageView implements OnScaleGestureListener {
getEdgesHelper(edges);
final float scale = mRenderer.scale;
mRenderer.centerX += Math.ceil(edges.left / scale);
mRenderer.centerY += Math.ceil(edges.top / scale);
}
public void setTouchEnabled(boolean enabled) {
@@ -197,11 +197,13 @@ public class CropView extends TiledImageView implements OnScaleGestureListener {
float squaredDist = (mFirstX - x) * (mFirstX - x) + (mFirstY - y) * (mFirstY - y);
float slop = config.getScaledTouchSlop() * config.getScaledTouchSlop();
long now = System.currentTimeMillis();
// only do this if it's a small movement
if (mTouchCallback != null &&
squaredDist < slop &&
if (mTouchCallback != null) {
// only do this if it's a small movement
if (squaredDist < slop &&
now < mTouchDownTime + ViewConfiguration.getTapTimeout()) {
mTouchCallback.onTap();
mTouchCallback.onTap();
}
mTouchCallback.onTouchUp();
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2013 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.
*/
/* Copied from Launcher3 */
package com.android.wallpapercropper;
import android.app.Activity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
public class TranslucentDecor {
private static final int SYSTEM_UI_FLAG_TRANSPARENT_STATUS = 0x00001000;
private static final int SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION = 0x00002000;
// Replace with SDK constants when available.
public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;
public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;
// Behave properly on early K builds.
public static final boolean SYSUI_SUPPORTED = !hasSystemUiFlag("ALLOW_TRANSIENT") &&
hasSystemUiFlag("TRANSPARENT_STATUS") &&
hasSystemUiFlag("TRANSPARENT_NAVIGATION");
public static final boolean WM_SUPPORTED =
hasWindowManagerFlag("TRANSLUCENT_STATUS") &&
hasWindowManagerFlag("TRANSLUCENT_NAVIGATION");
private final View mTarget;
public TranslucentDecor(View target) {
mTarget = target;
}
public void requestTranslucentDecor(boolean translucent) {
int sysui = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
if (WM_SUPPORTED && mTarget.getContext() instanceof Activity) {
Window w = ((Activity) mTarget.getContext()).getWindow();
int wmFlags = FLAG_TRANSLUCENT_STATUS | FLAG_TRANSLUCENT_NAVIGATION;
if (translucent) {
w.addFlags(wmFlags);
} else {
w.clearFlags(wmFlags);
}
} else if (SYSUI_SUPPORTED) { // Remove when droidfood platform is updated
if (translucent) {
sysui |= SYSTEM_UI_FLAG_TRANSPARENT_STATUS | SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION;
}
}
mTarget.setSystemUiVisibility(sysui);
}
private static boolean hasWindowManagerFlag(String name) {
try {
return WindowManager.LayoutParams.class.getField("FLAG_" + name) != null;
} catch (NoSuchFieldException e) {
return false;
}
}
private static boolean hasSystemUiFlag(String name) {
try {
return View.class.getField("SYSTEM_UI_FLAG_" + name) != null;
} catch (NoSuchFieldException e) {
return false;
}
}
}

View File

@@ -75,6 +75,9 @@ public class WallpaperCropActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
if (!enableRotation()) {
setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT);
}
}
protected void init() {
@@ -99,6 +102,12 @@ public class WallpaperCropActivity extends Activity {
cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
}
});
TranslucentDecor transparentDecor = new TranslucentDecor(findViewById(R.id.wallpaper_root));
transparentDecor.requestTranslucentDecor(true);
}
public boolean enableRotation() {
return getResources().getBoolean(R.bool.allow_rotation);
}
public static String getSharedPreferencesKey() {
@@ -162,7 +171,6 @@ public class WallpaperCropActivity extends Activity {
}
protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) {
BitmapCropTask cropTask = new BitmapCropTask(this,
filePath, null, 0, 0, true, false, null);
final Point bounds = cropTask.getImageBounds();
@@ -200,7 +208,7 @@ public class WallpaperCropActivity extends Activity {
}
}
};
BitmapCropTask cropTask = new BitmapCropTask(res, resId,
BitmapCropTask cropTask = new BitmapCropTask(this, res, resId,
crop, outSize.x, outSize.y,
true, false, onEndCrop);
cropTask.execute();
@@ -213,9 +221,11 @@ public class WallpaperCropActivity extends Activity {
protected void cropImageAndSetWallpaper(Uri uri,
OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
// Get the crop
// Get the crop
Point inSize = mCropView.getSourceDimensions();
boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
Point minDims = new Point();
Point maxDims = new Point();
Display d = getWindowManager().getDefaultDisplay();
@@ -226,12 +236,12 @@ public class WallpaperCropActivity extends Activity {
int maxDim = Math.max(maxDims.x, maxDims.y);
final int minDim = Math.min(minDims.x, minDims.y);
int defaultWidth;
int defaultWallpaperWidth;
if (isScreenLarge(getResources())) {
defaultWidth = (int) (maxDim *
defaultWallpaperWidth = (int) (maxDim *
wallpaperTravelToScreenWidthRatio(maxDim, minDim));
} else {
defaultWidth = Math.max((int)
defaultWallpaperWidth = Math.max((int)
(minDim * WALLPAPER_SCREENS_SPAN), maxDim);
}
@@ -256,12 +266,17 @@ public class WallpaperCropActivity extends Activity {
// ADJUST CROP WIDTH
// Extend the crop all the way to the right, for parallax
float extraSpaceToRight = inSize.x - cropRect.right;
// (or all the way to the left, in RTL)
float extraSpace = ltr ? inSize.x - cropRect.right : cropRect.left;
// Cap the amount of extra width
float maxExtraSpace = defaultWidth / cropScale - cropRect.width();
extraSpaceToRight = Math.min(extraSpaceToRight, maxExtraSpace);
float maxExtraSpace = defaultWallpaperWidth / cropScale - cropRect.width();
extraSpace = Math.min(extraSpace, maxExtraSpace);
cropRect.right += extraSpaceToRight;
if (ltr) {
cropRect.right += extraSpace;
} else {
cropRect.left -= extraSpace;
}
// ADJUST CROP HEIGHT
if (isPortrait) {
@@ -287,7 +302,7 @@ public class WallpaperCropActivity extends Activity {
}
}
};
BitmapCropTask cropTask = new BitmapCropTask(uri,
BitmapCropTask cropTask = new BitmapCropTask(this, uri,
cropRect, outWidth, outHeight, true, false, onEndCrop);
if (onBitmapCroppedHandler != null) {
cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
@@ -299,7 +314,7 @@ public class WallpaperCropActivity extends Activity {
public void onBitmapCropped(byte[] imageBytes);
}
protected class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
protected static class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
Uri mInUri = null;
Context mContext;
String mInFilePath;
@@ -309,7 +324,6 @@ public class WallpaperCropActivity extends Activity {
RectF mCropBounds = null;
int mOutWidth, mOutHeight;
int mRotation = 0; // for now
protected final WallpaperManager mWPManager;
String mOutputFormat = "jpg"; // for now
boolean mSetWallpaper;
boolean mSaveCroppedBitmap;
@@ -324,7 +338,6 @@ public class WallpaperCropActivity extends Activity {
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mContext = c;
mInFilePath = filePath;
mWPManager = WallpaperManager.getInstance(getApplicationContext());
init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
@@ -332,24 +345,23 @@ public class WallpaperCropActivity extends Activity {
RectF cropBounds, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mInImageBytes = imageBytes;
mWPManager = WallpaperManager.getInstance(getApplicationContext());
init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
public BitmapCropTask(Uri inUri,
public BitmapCropTask(Context c, Uri inUri,
RectF cropBounds, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mContext = c;
mInUri = inUri;
mWPManager = WallpaperManager.getInstance(getApplicationContext());
init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
public BitmapCropTask(Resources res, int inResId,
public BitmapCropTask(Context c, Resources res, int inResId,
RectF cropBounds, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mContext = c;
mInResId = inResId;
mResources = res;
mWPManager = WallpaperManager.getInstance(getApplicationContext());
init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
@@ -385,7 +397,7 @@ public class WallpaperCropActivity extends Activity {
try {
if (mInUri != null) {
mInStream = new BufferedInputStream(
getContentResolver().openInputStream(mInUri));
mContext.getContentResolver().openInputStream(mInUri));
} else if (mInFilePath != null) {
mInStream = mContext.openFileInput(mInFilePath);
} else if (mInImageBytes != null) {
@@ -426,16 +438,17 @@ public class WallpaperCropActivity extends Activity {
regenerateInputStream();
if (mNoCrop && mInStream != null) {
WallpaperManager wallpaperManager = null;
if (mSetWallpaper) {
wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext());
}
if (mSetWallpaper && mNoCrop && mInStream != null) {
try {
mWPManager.setStream(mInStream);
wallpaperManager.setStream(mInStream);
} catch (IOException e) {
Log.w(LOGTAG, "cannot write stream to wallpaper", e);
failure = true;
}
if (mOnEndRunnable != null) {
mOnEndRunnable.run();
}
return !failure;
}
if (mInStream != null) {
@@ -509,7 +522,9 @@ public class WallpaperCropActivity extends Activity {
(int) returnRect.height(), Bitmap.Config.ARGB_8888);
if (tmp != null) {
Canvas c = new Canvas(tmp);
c.drawBitmap(crop, m, new Paint());
Paint p = new Paint();
p.setFilterBitmap(true);
c.drawBitmap(crop, m, p);
crop = tmp;
}
} else if (mRotation > 0) {
@@ -534,26 +549,18 @@ public class WallpaperCropActivity extends Activity {
ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
// If we need to set to the wallpaper, set it
if (mSetWallpaper && mWPManager != null) {
if (mWPManager == null) {
Log.w(LOGTAG, "no wallpaper manager");
failure = true;
} else {
try {
byte[] outByteArray = tmpOut.toByteArray();
mWPManager.setStream(new ByteArrayInputStream(outByteArray));
if (mOnBitmapCroppedHandler != null) {
mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
}
} catch (IOException e) {
Log.w(LOGTAG, "cannot write stream to wallpaper", e);
failure = true;
if (mSetWallpaper && wallpaperManager != null) {
try {
byte[] outByteArray = tmpOut.toByteArray();
wallpaperManager.setStream(new ByteArrayInputStream(outByteArray));
if (mOnBitmapCroppedHandler != null) {
mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
}
} catch (IOException e) {
Log.w(LOGTAG, "cannot write stream to wallpaper", e);
failure = true;
}
}
if (mOnEndRunnable != null) {
mOnEndRunnable.run();
}
} else {
Log.w(LOGTAG, "cannot compress bitmap");
failure = true;
@@ -569,8 +576,9 @@ public class WallpaperCropActivity extends Activity {
@Override
protected void onPostExecute(Boolean result) {
setResult(Activity.RESULT_OK);
finish();
if (mOnEndRunnable != null) {
mOnEndRunnable.run();
}
}
}