Gauss Fuzzy Android
Prerequisite: Current requirements require users to see the ambiguous background of opening applications every time they slide down the status bar. The following introduction focuses on the implementation of this requirement.
Here are some ways to use and see them
Method 1:
Get the current screen shot (using SurfaceControl.screenshot) and process it in high-speed mode if the result is null Instead of using wallpaper (in order to consider the compression of wide screen wallpaper or non-home wallpaper), Layer Drawable is used after acquisition to take the resulting Drawable as the background of the current application, which not only achieves the ambiguous effect, but also saves the content of the current program. (Prevents wallpaper from being easily blurred when the color of the wallpaper is similar to the content of the current program.) Question)
Method 2:
Get the system wallpaper, cut, and synthesize the cut wallpaper and a translucent picture (size should be noted). This is not directly used by Layer Drawable, but by Canvas. Then the synthesized wallpaper is blurred by Gauss.Note: Method 2 actually needs to cut wallpaper in the process of using. This can not be tailored. It needs to copy the wallpaper first. A Bitmap object can only be operated on. In addition, memory overflow is prone to occur during subsequent synthesis and fuzzification. The following methods can be used to solve this problem. Of course, it is necessary to call Bitmap's receyle() method in time for recovery.
New Bitmap = bmp. copy (Bitmap. Config. ARGB_4444, true); //Use ARGB_4444 to reduce memory usage
Because the two methods are used separately in different projects, the advantages and disadvantages of each method can be combined with the actual situation to achieve the relevant requirements.
Method 3:
The above method is mainly realized by using java, that is, the method of getting bitmap is different, and the actual method of fuzzy processing is exactly the same. That is, RenderScript and cript Intrinsic Blur are used to deal with all the above methods. After learning from other people's achievements, it is found that there is also the part of using C to achieve fuzzy processing, which temporarily does not compare the performance differences. At the same time, this method also uses Su. RfaceControl. screenshot To get bitmap resources.
Note: You need to add <uses-permission android:name="android.permission.READ_FRAME_BUFFER"/> At the same time, system signature is required.
The source code of method 1 is as follows:
private static final int BLUR_RADIUS = 3; private static final int SCALE_RATIO = 8;
public void blur(){
Bitmap mBackBitmap = getScreenshot(context, BLUR_RADIUS);
Drawable backgroundDrawable = null;
if (mBackBitmap != null) {
backgroundDrawable = new BitmapDrawable(mBackBitmap);
} else {
Log.i(TAG, "mBackBitmap is null.");
WallpaperManager wallpaperManager = WallpaperManager.getInstance(mDialogContext);
backgroundDrawable = wallpaperManager.getDrawable();
}
if (backgroundDrawable != null) {
getWindow().getDecorView().setBackground(new LayerDrawable(new Drawable[]{backgroundDrawable,
context.getResources().getDrawable(R.drawable.ali_poweroff_background)}));
}
}
private Bitmap getScreenshot(Context context, int radius) {
long start = System.currentTimeMillis();
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
DisplayMetrics displayMetrics = new DisplayMetrics();
Matrix displayMatrix = new Matrix();
display.getRealMetrics(displayMetrics);
final int w = displayMetrics.widthPixels;
final int h = displayMetrics.heightPixels;
float[] dims = {w, h};
float degrees = getDegreesForRotation(display.getRotation());
boolean requiresRotation = (degrees > 0);
if (requiresRotation) {
// Get the dimensions of the device in its native orientation
displayMatrix.reset();
displayMatrix.preRotate(-degrees);
displayMatrix.mapPoints(dims);
dims[0] = Math.abs(dims[0]);
dims[1] = Math.abs(dims[1]);
}
Bitmap bp = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
if (bp == null) return null;
//clip bitmap
Bitmap ss = Bitmap.createBitmap((int) dims[0]/SCALE_RATIO, (int) dims[1]/SCALE_RATIO, Bitmap.Config.ARGB_8888);
if (ss == null) return null;
Canvas c = new Canvas(ss);
c.clipRect(0, 0, dims[0] / SCALE_RATIO, dims[1] / SCALE_RATIO);
Rect srcRect = new Rect(0, 0, bp.getWidth(), bp.getHeight());
Rect dstRect = new Rect(0, 0, ss.getWidth(), ss.getHeight());
c.drawBitmap(bp, srcRect, dstRect, null);
c.setBitmap(null);
bp.recycle();
bp = ss;
//rotate bitmap
if (requiresRotation) {
ss = Bitmap.createBitmap(w / SCALE_RATIO, h / SCALE_RATIO, Bitmap.Config.ARGB_8888);
if (ss == null) return null;
c = new Canvas(ss);
c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
c.rotate(degrees);
c.translate(-dims[0] / (2 * SCALE_RATIO), -dims[1] / (2 * SCALE_RATIO));
c.drawBitmap(bp, 0, 0, null);
c.setBitmap(null);
bp.recycle();
bp = ss;
}
//blur bitmap
Bitmap bitmap = bp.copy(bp.getConfig(), true);
final RenderScript rs = RenderScript.create(context);
final Allocation input = Allocation.createFromBitmap(rs, bp, Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius(radius);
script.setInput(input);
script.forEach(output);
output.copyTo(bitmap);
long end = System.currentTimeMillis();
Log.d(TAG, "Take time " + (end - start));
return bitmap;
}
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;
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient android:name="poweroff_background"
android:startColor="#e5000000"
android:endColor="#7f000000"
android:angle="90"
/>
</shape>
Method 2 source code is as follows:
private Bitmap blur_wallpaper = null;
public void applyBlur() {
Log.d(TAG,"applyBlur ------- ");
if(null != blur_wallpaper && !blur_wallpaper.isRecycled()){//Recycle variables that last saved wallpaper
Log.d(TAG,"applyBlur blur_wallpaper isRecycled");
setBackgroundResource(R.drawable.backgoud_bulr);
blur_wallpaper.recycle();
blur_wallpaper = null;
}
if(wallpaperManager == null){
wallpaperManager = WallpaperManager.getInstance(this.getContext());
}
Drawable wallpaperDrawable = wallpaperManager.getDrawable();
Bitmap bmp = ((BitmapDrawable) wallpaperDrawable).getBitmap();
Bitmap newBitmap = bmp;
if(null == newBitmap){
Log.d(TAG,"applyBlur newBitmap is null" );
if(blur_wallpaper == null){
setBackgroundResource(R.drawable.backgoud_bulr_default);
blur_wallpaper = ((BitmapDrawable)getResources().getDrawable(R.drawable.backgoud_bulr_default)).getBitmap();
}
return;
}else if(!newBitmap.isMutable()){
int w = bmp.getWidth();
int h = bmp.getHeight();
Log.d(TAG,"applyBlur w=" + w + " h=" + h);
Log.d(TAG,"applyBlur not isMutable");
try {
newBitmap = bmp.copy(Bitmap.Config.ARGB_4444, true);//Reducing memory usage with ARGB_4444
} catch (Exception e) {
Log.d(TAG,"bitmap copy error,out of memory");
if(null != bmp && !bmp.isRecycled()){
// bmp.recycle();
bmp = null;
}
if(null != newBitmap && !newBitmap.isRecycled()){
newBitmap.recycle();
newBitmap = null;
}
setBackgroundResource(R.drawable.backgoud_bulr_default);
blur_wallpaper = ((BitmapDrawable)getResources().getDrawable(R.drawable.backgoud_bulr_default)).getBitmap();
Log.d(TAG,"use default background");
return ;
}
}
newBitmap = mPictureUtil.setAndcropWallpaper(mContext, newBitmap);
if(null == newBitmap){
Toast.makeText(mContext, R.string.update_status_bar_ground_error, Toast.LENGTH_SHORT).show();
setBackgroundResource(R.drawable.backgoud_bulr_default);
blur_wallpaper = ((BitmapDrawable)getResources().getDrawable(R.drawable.backgoud_bulr_default)).getBitmap();
Log.d(TAG,"use default background----");
return;
}
Canvas canvas = new Canvas(newBitmap);
Drawable backgoud_bulr = this.getResources().getDrawable(R.drawable.backgoud_bulr);//Translucent black background
Bitmap bitmap_backgoud_bulr = ((BitmapDrawable)backgoud_bulr).getBitmap();
canvas.drawBitmap(bitmap_backgoud_bulr, 0, 0, null );
canvas.save(Canvas.ALL_SAVE_FLAG);
//Store newly synthesized pictures
canvas.restore();
if(bmp != null && !bmp.isRecycled()){
Log.d(TAG,"applyBlur bmp.isRecycled");
// bmp.recycle();
bmp = null;
}
if(bitmap_backgoud_bulr != null && !bitmap_backgoud_bulr.isRecycled()){
Log.d(TAG,"applyBlur bitmap_backgoud_bulr.isRecycled");
bitmap_backgoud_bulr.recycle();
bitmap_backgoud_bulr = null;
backgoud_bulr = null;
}
blur_wallpaper = mPictureUtil.blur(mContext, newBitmap);
Drawable background = new BitmapDrawable(getResources(), blur_wallpaper);
setBackground(background);
if(null != newBitmap && !newBitmap.isRecycled()){
Log.d(TAG,"blur bkg.isRecycled");
newBitmap.recycle();
newBitmap = null;
}
}
/**
* @Title: PictureUtil.java
* @Package com.doov.systemui.utils
* @Description: TODO(Describe what the document does in one sentence.
* @author
* @date 2015 7 August 2000, 3:54:46 p.m.
* @version V1.0
*/
package com.doov.systemui.utils;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
/**
* @ClassName: PictureUtil
* @Description:Picture processing
* @author zhang.le
* @date 2015 7 August 2000, 3:54:46 p.m.
*
*/
public class PictureUtil {
private static final String TAG = "PictureUtil";
public final static int mScal = 2;
private final boolean DEBUG = true;
/**
*
*Gauss Mode Processing
* @param context
* @param bkg
* @return Bitmap Return type
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public Bitmap blur(Context context,Bitmap bkg) {
long startMs = System.currentTimeMillis();
float radius = 25;
bkg = small(bkg);
bkg = bkg.copy(bkg.getConfig(), true);
final RenderScript rs = RenderScript.create(context);
final Allocation input = Allocation.createFromBitmap(rs, bkg, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs,
Element.U8_4(rs));
script.setRadius(radius);
script.setInput(input);
script.forEach(output);
output.copyTo(bkg);
rs.destroy();
script.destroy();
input.destroy();
output.destroy();
Log.d(TAG, "blur take away:" + (System.currentTimeMillis() - startMs) + "ms");
return bkg;
}
private static Bitmap small(Bitmap bitmap) {
Matrix matrix = new Matrix();
matrix.postScale(1f/mScal, 1f/mScal); // Ratio of length and width amplification to reduction
Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
return resizeBmp;
}
/**
*
* Cut pictures
* @param context
* @param wallpaper
* @return Bitmap
*/
public Bitmap setAndcropWallpaper(Context context,Bitmap wallpaper) {
Bitmap targetBitmap = null;
if (wallpaper != null) {
try {
int wallpaperWidth = wallpaper.getWidth();
int wallpaperHeight = wallpaper.getHeight();
DisplayMetrics dm = new DisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(dm);
int screenWidth = dm.widthPixels;// 1080
int screenHeight = dm.heightPixels;// 1920
float defaultScreen = (float)screenHeight / (float)screenWidth;
Log.d(TAG, "defaultScreen=" + defaultScreen);
if (defaultScreen < 1) {
defaultScreen = (float)screenWidth / (float)screenHeight;
}
float bitmapSize = (float)wallpaperHeight /(float)wallpaperWidth;
int disWidth = 0;
int disHeight = 0;
int captureBitmapWidth = wallpaperWidth;
int captureBitmapHeight = wallpaperHeight;
Log.d(TAG, "defaultScreen=" + defaultScreen + " bitmapSize="
+ bitmapSize);
if (defaultScreen > bitmapSize) { // bitmapHeight is min , capture bitmapWidth
captureBitmapWidth = (int) ((screenWidth * wallpaperHeight) / screenHeight);
disWidth = wallpaperWidth - captureBitmapWidth;
} else if (defaultScreen < bitmapSize) {
captureBitmapHeight = (int) ((wallpaperWidth * screenHeight) / screenWidth);
disHeight = wallpaperHeight - captureBitmapHeight;
}
if (DEBUG) {
Log.d(TAG, "setAndcropWallpaper ----- disWidth="
+ disWidth + ",disHeight=" + disHeight
+ ",captureBitmapWidth=" + captureBitmapWidth
+ ",captureBitmapHeight=" + captureBitmapHeight
+ " screenWidth=" + screenWidth + " screenHeight="
+ screenHeight);
}
if (disWidth < 0 || disHeight < 0) {
return null;
}
targetBitmap = Bitmap.createBitmap(wallpaper, disWidth / 2,
disHeight / 2, captureBitmapWidth, captureBitmapHeight);
float scaleWidth = (float) ((float) captureBitmapWidth / screenWidth);
float scaleHeight = (float) ((float) captureBitmapHeight / screenHeight);
Log.d(TAG, "scaleWidth=" + scaleWidth + " scaleHeight="
+ scaleHeight);
if ((targetBitmap != null)
&& (scaleWidth != 1 || scaleHeight != 1)) {
Matrix matrix = new Matrix();
/**
* After processing, the image size is smaller than the screen size. The original image proportion is the same as the screen proportion, but the size is larger than the screen size.
*/
if (scaleWidth != 0.0f && scaleHeight != 0.0f
&& (scaleWidth != 1.0f || scaleHeight != 1.0f)) {//
scaleWidth = 1.0f / scaleWidth;
scaleHeight = 1.0f / scaleHeight;
Log.d(TAG, "---scaleWidth=" + scaleWidth + " scaleHeight=" + scaleHeight);
}
matrix.postScale(scaleWidth, scaleHeight);
int width = targetBitmap.getWidth();
int height = targetBitmap.getHeight();
Log.d(TAG, "---width=" + width + " height=" + height);
targetBitmap = Bitmap.createBitmap(targetBitmap, 0, 0,
screenWidth > width ? width : screenWidth,
screenHeight > height ? height : screenHeight,
matrix, true);
}
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
}
return targetBitmap;
}
}
Method 3 source code
protected static final int MSG_SCREEN_SHOT = 2031;
public boolean interceptTouchEvent(MotionEvent event) {
//......
//zhangle add start
int action = event.getAction();
if (MotionEvent.ACTION_DOWN == action) {
if (!mExpandedVisible) {
boolean hasScreenShotMsg = myHandler.hasMessages(MSG_SCREEN_SHOT);
LogD.d(TAG, "interceptTouchEvent hasScreenShotMsg = " + hasScreenShotMsg);
if (!hasScreenShotMsg) {
Log.d(TAG, " sendEmptyMessage MSG_SCREEN_SHOT currentTimeMillis = " + System.currentTimeMillis());
myHandler.sendEmptyMessage(MSG_SCREEN_SHOT);
}
}
}
//zhangel add end
return false;
}
private Bitmap mScreenShotBg;
protected void setScreenShotBitmap(Bitmap bitmap) {
mScreenShotBg = bitmap;
}
public void recyleScreenShotBg(){
if (mScreenShotBg != null) {
mScreenShotBg.recycle();
mScreenShotBg = null;
}
}
@Override
public void draw(Canvas canvas) {
if (canvas == null) {
return;
}
if (mScreenShotBg != null) {
Bitmap bp = mScreenShotBg;
Rect dstRect = new Rect(0, 0, getWidth(), (int) getFullHeight());
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
canvas.drawBitmap(bp, new Rect(0, 0, bp.getWidth(), bp.getHeight()), dstRect, paint);
}
super.draw(canvas);
}
//zhangle add start
private Handler myHandler = new Handler(){
@Override
public void dispatchMessage(Message msg) {
switch (msg.what) {
case MSG_SCREEN_SHOT:
Xlog.d(TAG, "MSG_SCREEN_SHOT.");
Bitmap screenShotBitmap = screenshotFocusedWindow(mDisplayMetrics.widthPixels,
mDisplayMetrics.heightPixels);
if (screenShotBitmap != null) {
mNotificationPanel.setScreenShotBitmap(screenShotBitmap);
}
break;
default:
break;
}
}
};
private Bitmap screenshotFocusedWindow(int maxWidth, int maxHeight) {
long beginScreenShot = System.currentTimeMillis();
int rot = mDisplay.getRotation();
Rect frame = new Rect();
float degrees = 0f;
switch (rot) {
case Surface.ROTATION_90:
degrees = 360f - 90f;
break;
case Surface.ROTATION_180:
degrees = 360f - 180f;
break;
case Surface.ROTATION_270:
degrees = 360f - 270f;
break;
default:
degrees = 0f;
break;
}
int mNavSize = 0;
try {
boolean showNav = mWindowManagerService.hasNavigationBar();//IWindowManager
if (showNav) {
mNavSize = mContext.getResources().getDimensionPixelSize(
R.dimen.navigation_bar_size);
}
} catch (RemoteException ex) {
// no window manager? good luck with that
Slog.e(TAG, "resolve navigationbar layout fail");
}
if (mNavSize > 0) {
if (maxHeight > maxWidth) {
maxHeight += mNavSize;
} else {
maxWidth += mNavSize;
}
}
Matrix matrix = new Matrix();
int dw = maxWidth;
int dh = maxHeight;
if (DEBUG) Log.d("screenshot", "bitmap dw =" + maxWidth + " dh = " + maxHeight);
frame.set(0, 0/* getStatusBarHeight() */, dw, dh);
float dims[] = {
dw, dh
};
boolean requiresRotation = (degrees > 0);
if (requiresRotation) {
// Get the dimensions of the device in its native orientation
matrix.reset();
matrix.preRotate(-degrees);
matrix.mapPoints(dims);
dims[0] = Math.abs(dims[0]);
dims[1] = Math.abs(dims[1]);
}
if (frame.isEmpty()) {
return null;
}
if (DEBUG) Log.d("screenshot", "bitmap width =" + dims[0] + "height = " + dims[1]);
Bitmap bp = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
// The screenshot() interface may fail. If it fail, it will return null.
// If the screenshot is null, the statusbar will be transparent.
if (bp == null) {
return null;
}
final int SCALE_RATIO = 8;
if (requiresRotation) {
// Rotate the screenshot to the current orientation
Bitmap ss = Bitmap.createBitmap(dw / SCALE_RATIO, dh / SCALE_RATIO,
Bitmap.Config.ARGB_8888);
if (DEBUG)
Log.d("screenshot", "Canvas width =" + dims[0] + " height = " + dims[1]);
if (ss == null) {
return null;
}
Canvas c = new Canvas(ss);
c.clipRect(0, frame.top / SCALE_RATIO, dw / SCALE_RATIO, dh / SCALE_RATIO);
if (mNavSize > 0) {
c.clipRect(0, 0, (dw - mNavSize) / SCALE_RATIO, dh / SCALE_RATIO);
}
c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
c.rotate(degrees);
c.translate(-dims[0] / (2 * SCALE_RATIO), -dims[1] / (2 * SCALE_RATIO));
// c.drawBitmap(bp, 0, 0, null);
Rect dstRect = new Rect(0, 0, ss.getHeight(), ss.getWidth());
c.drawBitmap(bp, new Rect(0, 0, bp.getWidth(), bp.getHeight()), dstRect, null);
Paint paint = new Paint();
// Reset the screen shot color alpha for text show clearly.
// 80% black
paint.setColor(mContext.getResources().getColor(R.color.notification_background_color));
/* YUNOS END */
c.drawRect(dstRect, paint);
c.setBitmap(null);
bp.recycle();
bp = ss;
} else {
Bitmap ss = Bitmap.createBitmap(dw / SCALE_RATIO, dh / SCALE_RATIO,
Bitmap.Config.ARGB_8888);
if (ss == null) {
return null;
}
Canvas c = new Canvas(ss);
c.clipRect(0, frame.top / SCALE_RATIO, dw / SCALE_RATIO, dh / SCALE_RATIO);
if (mNavSize > 0) {
c.clipRect(0, 0, dw / SCALE_RATIO, (dh - mNavSize) / SCALE_RATIO);
}
// c.drawBitmap(bp, 0, 0, null);
Rect dstRect = new Rect(0, 0, ss.getWidth(), ss.getHeight());
c.drawBitmap(bp, new Rect(0, 0, bp.getWidth(), bp.getHeight()), dstRect, null);
Paint paint = new Paint();
// Reset the screen shot color alpha for text show clearly.
// 80% black
paint.setColor(mContext.getResources().getColor(R.color.notification_background_color));
c.drawRect(dstRect, paint);
c.setBitmap(null);
bp.recycle();
bp = ss;
}
// Invoke jni with thread safe
bp = FrostedGlassUtil.getInstance().convertToBlur(bp, 20);
return bp;
}
//zhangle add end
package com.android.systemui.utils;
import android.graphics.Bitmap;
public class FrostedGlassUtil {
private volatile static FrostedGlassUtil mFrostedGlassUtil;
/*YUNOS BEGIN*/
//##module(SystemUI)
//##date:2013/3/29 ##author:sunchen.sc@alibaba-inc.com##BugID:104943
//Invoke jni with thread safe
public static FrostedGlassUtil getInstance() {
if (mFrostedGlassUtil == null) {
synchronized (FrostedGlassUtil.class) {
if (mFrostedGlassUtil == null) {
mFrostedGlassUtil = new FrostedGlassUtil();
}
}
}
return mFrostedGlassUtil;
}
/*YUNOS END*/
public native void clearColor(Bitmap image, int color);
public native void imageBlur(Bitmap srcBitmap, Bitmap dstBitmap);
public native void boxBlur(Bitmap srcBitmap, int radius);
public native void stackBlur(Bitmap srcBitmap, int radius);
public native void oilPaint(Bitmap srcBitmap, int radius);
public native void colorWaterPaint(Bitmap srcBitmap, int radius);
/*YUNOS BEGIN*/
//##module(SystemUI)
//##date:2013/3/29 ##author:sunchen.sc@alibaba-inc.com##BugID:104943
//Invoke jni with thread safe
public synchronized Bitmap convertToBlur(Bitmap bmp, int radius) {
long beginBlur = System.currentTimeMillis();
stackBlur(bmp, radius);
return bmp;
}
static {
// load frosted glass lib
System.loadLibrary("frostedGlass");
}
/*YUNOS END*/
}

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libfrostedGlass
LOCAL_SRC_FILES := frostedGlass.c bitmapPort.c imageProcess.c
#LOCAL_LDLIBS := -llog -ljnigraphics
LOCAL_SHARED_LIBRARIES += \
liblog libjnigraphics
include $(BUILD_SHARED_LIBRARY)