LayoutLib: Original import of Honeycomb's layoutlib. do not merge.

frameworks/base.git @ f0a53435f1

Change-Id: Ibc215751693dc7650683b61bb458f7c8beaf8060
This commit is contained in:
Xavier Ducrohet
2011-02-07 21:08:10 -08:00
parent 2050de5b9a
commit 4b52ec49fe
141 changed files with 17642 additions and 8420 deletions

4
tools/layoutlib/README Normal file
View File

@@ -0,0 +1,4 @@
Layoutlib is a custom version of the android View framework designed to run inside Eclipse.
The goal of the library is to provide layout rendering in Eclipse that are very very close to their rendering on devices.
None of the com.android.* or android.* classes in layoutlib run on devices.

View File

@@ -4,9 +4,10 @@
<classpathentry kind="src" path="tests"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
<classpathentry combineaccessrules="false" kind="src" path="/layoutlib_api"/>
<classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_SRC/dalvik/libcore/xml/src/main/java"/>
<classpathentry kind="var" path="ANDROID_OUT_FRAMEWORK/layoutlib.jar" sourcepath="/ANDROID_SRC/frameworks/base/core/java"/>
<classpathentry kind="var" path="ANDROID_OUT_FRAMEWORK/ninepatch.jar" sourcepath="/ANDROID_SRC/development/tools/ninepatch/src"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/layoutlib_api/layoutlib_api-prebuilt.jar"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/ninepatch/ninepatch-prebuilt.jar"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/tools-common/tools-common-prebuilt.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@@ -17,13 +17,17 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_JAVA_RESOURCE_DIRS := resources
LOCAL_JAVA_LIBRARIES := \
kxml2-2.3.0 \
layoutlib_api \
ninepatch
layoutlib_api-prebuilt \
tools-common-prebuilt
LOCAL_STATIC_JAVA_LIBRARIES := temp_layoutlib
LOCAL_STATIC_JAVA_LIBRARIES := \
temp_layoutlib \
ninepatch-prebuilt
LOCAL_MODULE := layoutlib

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</merge>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginLeft="3dip"
android:layout_marginRight="5dip"/>
</merge>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginLeft="3dip"
android:layout_marginRight="15dip"/>
</merge>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</merge>

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2010 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 android.animation;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.animation.PropertyValuesHolder
*
* Through the layoutlib_create tool, the original native methods of PropertyValuesHolder have been
* replaced by calls to methods of the same name in this delegate class.
*
* Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
* around to map int to instance of the delegate.
*
* The main goal of this class' methods are to provide a native way to access setters and getters
* on some object. In this case we want to default to using Java reflection instead so the native
* methods do nothing.
*
*/
/*package*/ class PropertyValuesHolder_Delegate {
@LayoutlibDelegate
/*package*/ static int nGetIntMethod(Class<?> targetClass, String methodName) {
// return 0 to force PropertyValuesHolder to use Java reflection.
return 0;
}
@LayoutlibDelegate
/*package*/ static int nGetFloatMethod(Class<?> targetClass, String methodName) {
// return 0 to force PropertyValuesHolder to use Java reflection.
return 0;
}
@LayoutlibDelegate
/*package*/ static void nCallIntMethod(Object target, int methodID, int arg) {
// do nothing
}
@LayoutlibDelegate
/*package*/ static void nCallFloatMethod(Object target, int methodID, float arg) {
// do nothing
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2010 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 android.app;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.content.Context;
import android.os.Bundle;
/**
* Delegate used to provide new implementation of a select few methods of {@link Fragment}
*
* Through the layoutlib_create tool, the original methods of Fragment have been replaced
* by calls to methods of the same name in this delegate class.
*
* The methods being re-implemented are the ones responsible for instantiating Fragment objects.
* Because the classes of these objects are found in the project, these methods need access to
* {@link IProjectCallback} object. They are however static methods, so the callback is set
* before the inflation through {@link #setProjectCallback(IProjectCallback)}.
*/
public class Fragment_Delegate {
private static IProjectCallback sProjectCallback;
/**
* Sets the current {@link IProjectCallback} to be used to instantiate classes coming
* from the project being rendered.
*/
public static void setProjectCallback(IProjectCallback projectCallback) {
sProjectCallback = projectCallback;
}
/**
* Like {@link #instantiate(Context, String, Bundle)} but with a null
* argument Bundle.
*/
@LayoutlibDelegate
/*package*/ static Fragment instantiate(Context context, String fname) {
return instantiate(context, fname, null);
}
/**
* Create a new instance of a Fragment with the given class name. This is
* the same as calling its empty constructor.
*
* @param context The calling context being used to instantiate the fragment.
* This is currently just used to get its ClassLoader.
* @param fname The class name of the fragment to instantiate.
* @param args Bundle of arguments to supply to the fragment, which it
* can retrieve with {@link #getArguments()}. May be null.
* @return Returns a new fragment instance.
* @throws InstantiationException If there is a failure in instantiating
* the given fragment class. This is a runtime exception; it is not
* normally expected to happen.
*/
@LayoutlibDelegate
/*package*/ static Fragment instantiate(Context context, String fname, Bundle args) {
try {
if (sProjectCallback != null) {
Fragment f = (Fragment) sProjectCallback.loadView(fname,
new Class[0], new Object[0]);
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
f.mArguments = args;
}
return f;
}
return null;
} catch (ClassNotFoundException e) {
throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (java.lang.InstantiationException e) {
throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (IllegalAccessException e) {
throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (Exception e) {
throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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 android.content.res;
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
import android.util.AttributeSet;
import android.util.TypedValue;
/**
* Delegate used to provide new implementation of a select few methods of {@link Theme}
*
* Through the layoutlib_create tool, the original methods of Theme have been replaced
* by calls to methods of the same name in this delegate class.
*
*/
public class Resources_Theme_Delegate {
@LayoutlibDelegate
/*package*/ static TypedArray obtainStyledAttributes(
Resources thisResources, Theme thisTheme,
int[] attrs) {
return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
}
@LayoutlibDelegate
/*package*/ static TypedArray obtainStyledAttributes(
Resources thisResources, Theme thisTheme,
int resid, int[] attrs)
throws NotFoundException {
return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid, attrs);
}
@LayoutlibDelegate
/*package*/ static TypedArray obtainStyledAttributes(
Resources thisResources, Theme thisTheme,
AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(
set, attrs, defStyleAttr, defStyleRes);
}
@LayoutlibDelegate
/*package*/ static boolean resolveAttribute(
Resources thisResources, Theme thisTheme,
int resid, TypedValue outValue,
boolean resolveRefs) {
return RenderSessionImpl.getCurrentContext().resolveThemeAttribute(
resid, outValue, resolveRefs);
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Composite;
/**
* Delegate implementing the native methods of android.graphics.AvoidXfermode
*
* Through the layoutlib_create tool, the original native methods of AvoidXfermode have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original AvoidXfermode class.
*
* Because this extends {@link Xfermode_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
* {@link Xfermode_Delegate}.
*
*/
public class AvoidXfermode_Delegate extends Xfermode_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public Composite getComposite(int alpha) {
// FIXME
return null;
}
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Avoid Xfermodes are not supported in Layout Preview mode.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate(int opColor, int tolerance, int nativeMode) {
AvoidXfermode_Delegate newDelegate = new AvoidXfermode_Delegate();
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -1,278 +0,0 @@
/*
* Copyright (C) 2008 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 android.graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
public final class Bitmap extends _Original_Bitmap {
private BufferedImage mImage;
public Bitmap(File input) throws IOException {
super(1, true, null, -1);
mImage = ImageIO.read(input);
}
public Bitmap(InputStream is) throws IOException {
super(1, true, null, -1);
mImage = ImageIO.read(is);
}
Bitmap(BufferedImage image) {
super(1, true, null, -1);
mImage = image;
}
public BufferedImage getImage() {
return mImage;
}
// ----- overriden methods
public enum Config {
// these native values must match up with the enum in SkBitmap.h
ALPHA_8 (2),
RGB_565 (4),
ARGB_4444 (5),
ARGB_8888 (6);
Config(int ni) {
this.nativeInt = ni;
}
final int nativeInt;
/* package */ static Config nativeToConfig(int ni) {
return sConfigs[ni];
}
private static Config sConfigs[] = {
null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
};
}
@Override
public int getWidth() {
return mImage.getWidth();
}
@Override
public int getHeight() {
return mImage.getHeight();
}
/**
* Returns an immutable bitmap from the source bitmap. The new bitmap may
* be the same object as source, or a copy may have been made.
*/
public static Bitmap createBitmap(Bitmap src) {
return createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), null, false);
}
/**
* Returns an immutable bitmap from the specified subset of the source
* bitmap. The new bitmap may be the same object as source, or a copy may
* have been made.
*
* @param source The bitmap we are subsetting
* @param x The x coordinate of the first pixel in source
* @param y The y coordinate of the first pixel in source
* @param width The number of pixels in each row
* @param height The number of rows
*/
public static Bitmap createBitmap(Bitmap source, int x, int y,
int width, int height) {
return new Bitmap(source.mImage.getSubimage(x, y, width, height));
}
/**
* Returns an immutable bitmap from subset of the source bitmap,
* transformed by the optional matrix.
*
* @param source The bitmap we are subsetting
* @param x The x coordinate of the first pixel in source
* @param y The y coordinate of the first pixel in source
* @param width The number of pixels in each row
* @param height The number of rows
* @param m Option matrix to be applied to the pixels
* @param filter true if the source should be filtered.
* Only applies if the matrix contains more than just
* translation.
* @return A bitmap that represents the specified subset of source
* @throws IllegalArgumentException if the x, y, width, height values are
* outside of the dimensions of the source bitmap.
*/
public static Bitmap createBitmap(Bitmap source, int x, int y, int width,
int height, Matrix m, boolean filter) {
checkXYSign(x, y);
checkWidthHeight(width, height);
if (x + width > source.getWidth()) {
throw new IllegalArgumentException(
"x + width must be <= bitmap.width()");
}
if (y + height > source.getHeight()) {
throw new IllegalArgumentException(
"y + height must be <= bitmap.height()");
}
// check if we can just return our argument unchanged
if (!source.isMutable() && x == 0 && y == 0
&& width == source.getWidth() && height == source.getHeight()
&& (m == null || m.isIdentity())) {
return source;
}
if (m == null || m.isIdentity()) {
return new Bitmap(source.mImage.getSubimage(x, y, width, height));
}
int neww = width;
int newh = height;
Paint paint;
Rect srcR = new Rect(x, y, x + width, y + height);
RectF dstR = new RectF(0, 0, width, height);
/* the dst should have alpha if the src does, or if our matrix
doesn't preserve rectness
*/
boolean hasAlpha = source.hasAlpha() || !m.rectStaysRect();
RectF deviceR = new RectF();
m.mapRect(deviceR, dstR);
neww = Math.round(deviceR.width());
newh = Math.round(deviceR.height());
Canvas canvas = new Canvas(neww, newh);
canvas.translate(-deviceR.left, -deviceR.top);
canvas.concat(m);
paint = new Paint();
paint.setFilterBitmap(filter);
if (!m.rectStaysRect()) {
paint.setAntiAlias(true);
}
canvas.drawBitmap(source, srcR, dstR, paint);
return new Bitmap(canvas.getImage());
}
/**
* Returns a mutable bitmap with the specified width and height.
*
* @param width The width of the bitmap
* @param height The height of the bitmap
* @param config The bitmap config to create.
* @throws IllegalArgumentException if the width or height are <= 0
*/
public static Bitmap createBitmap(int width, int height, Config config) {
return new Bitmap(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB));
}
/**
* Returns a immutable bitmap with the specified width and height, with each
* pixel value set to the corresponding value in the colors array.
*
* @param colors Array of {@link Color} used to initialize the pixels.
* @param offset Number of values to skip before the first color in the
* array of colors.
* @param stride Number of colors in the array between rows (must be >=
* width or <= -width).
* @param width The width of the bitmap
* @param height The height of the bitmap
* @param config The bitmap config to create. If the config does not
* support per-pixel alpha (e.g. RGB_565), then the alpha
* bytes in the colors[] will be ignored (assumed to be FF)
* @throws IllegalArgumentException if the width or height are <= 0, or if
* the color array's length is less than the number of pixels.
*/
public static Bitmap createBitmap(int colors[], int offset, int stride,
int width, int height, Config config) {
checkWidthHeight(width, height);
if (Math.abs(stride) < width) {
throw new IllegalArgumentException("abs(stride) must be >= width");
}
int lastScanline = offset + (height - 1) * stride;
int length = colors.length;
if (offset < 0 || (offset + width > length)
|| lastScanline < 0
|| (lastScanline + width > length)) {
throw new ArrayIndexOutOfBoundsException();
}
// TODO: create an immutable bitmap...
throw new UnsupportedOperationException();
}
/**
* Returns a immutable bitmap with the specified width and height, with each
* pixel value set to the corresponding value in the colors array.
*
* @param colors Array of {@link Color} used to initialize the pixels.
* This array must be at least as large as width * height.
* @param width The width of the bitmap
* @param height The height of the bitmap
* @param config The bitmap config to create. If the config does not
* support per-pixel alpha (e.g. RGB_565), then the alpha
* bytes in the colors[] will be ignored (assumed to be FF)
* @throws IllegalArgumentException if the width or height are <= 0, or if
* the color array's length is less than the number of pixels.
*/
public static Bitmap createBitmap(int colors[], int width, int height,
Config config) {
return createBitmap(colors, 0, width, width, height, config);
}
public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
int dstHeight, boolean filter) {
Matrix m;
synchronized (Bitmap.class) {
// small pool of just 1 matrix
m = sScaleMatrix;
sScaleMatrix = null;
}
if (m == null) {
m = new Matrix();
}
final int width = src.getWidth();
final int height = src.getHeight();
final float sx = dstWidth / (float)width;
final float sy = dstHeight / (float)height;
m.setScale(sx, sy);
Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
synchronized (Bitmap.class) {
// do we need to check for null? why not just assign everytime?
if (sScaleMatrix == null) {
sScaleMatrix = m;
}
}
return b;
}
}

View File

@@ -1,566 +0,0 @@
/*
* Copyright (C) 2010 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 android.graphics;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import java.io.BufferedInputStream;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Creates Bitmap objects from various sources, including files, streams,
* and byte-arrays.
*/
public class BitmapFactory {
public static class Options {
/**
* Create a default Options object, which if left unchanged will give
* the same result from the decoder as if null were passed.
*/
public Options() {
inDither = true;
inScaled = true;
}
/**
* If set to true, the decoder will return null (no bitmap), but
* the out... fields will still be set, allowing the caller to query
* the bitmap without having to allocate the memory for its pixels.
*/
public boolean inJustDecodeBounds;
/**
* If set to a value > 1, requests the decoder to subsample the original
* image, returning a smaller image to save memory. The sample size is
* the number of pixels in either dimension that correspond to a single
* pixel in the decoded bitmap. For example, inSampleSize == 4 returns
* an image that is 1/4 the width/height of the original, and 1/16 the
* number of pixels. Any value <= 1 is treated the same as 1. Note: the
* decoder will try to fulfill this request, but the resulting bitmap
* may have different dimensions that precisely what has been requested.
* Also, powers of 2 are often faster/easier for the decoder to honor.
*/
public int inSampleSize;
/**
* If this is non-null, the decoder will try to decode into this
* internal configuration. If it is null, or the request cannot be met,
* the decoder will try to pick the best matching config based on the
* system's screen depth, and characteristics of the original image such
* as if it has per-pixel alpha (requiring a config that also does).
*/
public Bitmap.Config inPreferredConfig;
/**
* If dither is true, the decoder will attempt to dither the decoded
* image.
*/
public boolean inDither;
/**
* The pixel density to use for the bitmap. This will always result
* in the returned bitmap having a density set for it (see
* {@link Bitmap#setDensity(int) Bitmap.setDensity(int)). In addition,
* if {@link #inScaled} is set (which it is by default} and this
* density does not match {@link #inTargetDensity}, then the bitmap
* will be scaled to the target density before being returned.
*
* <p>If this is 0,
* {@link BitmapFactory#decodeResource(Resources, int)},
* {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
* and {@link BitmapFactory#decodeResourceStream}
* will fill in the density associated with the resource. The other
* functions will leave it as-is and no density will be applied.
*
* @see #inTargetDensity
* @see #inScreenDensity
* @see #inScaled
* @see Bitmap#setDensity(int)
* @see android.util.DisplayMetrics#densityDpi
*/
public int inDensity;
/**
* The pixel density of the destination this bitmap will be drawn to.
* This is used in conjunction with {@link #inDensity} and
* {@link #inScaled} to determine if and how to scale the bitmap before
* returning it.
*
* <p>If this is 0,
* {@link BitmapFactory#decodeResource(Resources, int)},
* {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
* and {@link BitmapFactory#decodeResourceStream}
* will fill in the density associated the Resources object's
* DisplayMetrics. The other
* functions will leave it as-is and no scaling for density will be
* performed.
*
* @see #inDensity
* @see #inScreenDensity
* @see #inScaled
* @see android.util.DisplayMetrics#densityDpi
*/
public int inTargetDensity;
/**
* The pixel density of the actual screen that is being used. This is
* purely for applications running in density compatibility code, where
* {@link #inTargetDensity} is actually the density the application
* sees rather than the real screen density.
*
* <p>By setting this, you
* allow the loading code to avoid scaling a bitmap that is currently
* in the screen density up/down to the compatibility density. Instead,
* if {@link #inDensity} is the same as {@link #inScreenDensity}, the
* bitmap will be left as-is. Anything using the resulting bitmap
* must also used {@link Bitmap#getScaledWidth(int)
* Bitmap.getScaledWidth} and {@link Bitmap#getScaledHeight
* Bitmap.getScaledHeight} to account for any different between the
* bitmap's density and the target's density.
*
* <p>This is never set automatically for the caller by
* {@link BitmapFactory} itself. It must be explicitly set, since the
* caller must deal with the resulting bitmap in a density-aware way.
*
* @see #inDensity
* @see #inTargetDensity
* @see #inScaled
* @see android.util.DisplayMetrics#densityDpi
*/
public int inScreenDensity;
/**
* When this flag is set, if {@link #inDensity} and
* {@link #inTargetDensity} are not 0, the
* bitmap will be scaled to match {@link #inTargetDensity} when loaded,
* rather than relying on the graphics system scaling it each time it
* is drawn to a Canvas.
*
* <p>This flag is turned on by default and should be turned off if you need
* a non-scaled version of the bitmap. Nine-patch bitmaps ignore this
* flag and are always scaled.
*/
public boolean inScaled;
/**
* If this is set to true, then the resulting bitmap will allocate its
* pixels such that they can be purged if the system needs to reclaim
* memory. In that instance, when the pixels need to be accessed again
* (e.g. the bitmap is drawn, getPixels() is called), they will be
* automatically re-decoded.
*
* For the re-decode to happen, the bitmap must have access to the
* encoded data, either by sharing a reference to the input
* or by making a copy of it. This distinction is controlled by
* inInputShareable. If this is true, then the bitmap may keep a shallow
* reference to the input. If this is false, then the bitmap will
* explicitly make a copy of the input data, and keep that. Even if
* sharing is allowed, the implementation may still decide to make a
* deep copy of the input data.
*/
public boolean inPurgeable;
/**
* This field works in conjuction with inPurgeable. If inPurgeable is
* false, then this field is ignored. If inPurgeable is true, then this
* field determines whether the bitmap can share a reference to the
* input data (inputstream, array, etc.) or if it must make a deep copy.
*/
public boolean inInputShareable;
/**
* Normally bitmap allocations count against the dalvik heap, which
* means they help trigger GCs when a lot have been allocated. However,
* in rare cases, the caller may want to allocate the bitmap outside of
* that heap. To request that, set inNativeAlloc to true. In these
* rare instances, it is solely up to the caller to ensure that OOM is
* managed explicitly by calling bitmap.recycle() as soon as such a
* bitmap is no longer needed.
*
* @hide pending API council approval
*/
public boolean inNativeAlloc;
/**
* The resulting width of the bitmap, set independent of the state of
* inJustDecodeBounds. However, if there is an error trying to decode,
* outWidth will be set to -1.
*/
public int outWidth;
/**
* The resulting height of the bitmap, set independent of the state of
* inJustDecodeBounds. However, if there is an error trying to decode,
* outHeight will be set to -1.
*/
public int outHeight;
/**
* If known, this string is set to the mimetype of the decoded image.
* If not know, or there is an error, it is set to null.
*/
public String outMimeType;
/**
* Temp storage to use for decoding. Suggest 16K or so.
*/
public byte[] inTempStorage;
private native void requestCancel();
/**
* Flag to indicate that cancel has been called on this object. This
* is useful if there's an intermediary that wants to first decode the
* bounds and then decode the image. In that case the intermediary
* can check, inbetween the bounds decode and the image decode, to see
* if the operation is canceled.
*/
public boolean mCancel;
/**
* This can be called from another thread while this options object is
* inside a decode... call. Calling this will notify the decoder that
* it should cancel its operation. This is not guaranteed to cancel
* the decode, but if it does, the decoder... operation will return
* null, or if inJustDecodeBounds is true, will set outWidth/outHeight
* to -1
*/
public void requestCancelDecode() {
mCancel = true;
requestCancel();
}
}
/**
* Decode a file path into a bitmap. If the specified file name is null,
* or cannot be decoded into a bitmap, the function returns null.
*
* @param pathName complete path name for the file to be decoded.
* @param opts null-ok; Options that control downsampling and whether the
* image should be completely decoded, or just is size returned.
* @return The decoded bitmap, or null if the image data could not be
* decoded, or, if opts is non-null, if opts requested only the
* size be returned (in opts.outWidth and opts.outHeight)
*/
public static Bitmap decodeFile(String pathName, Options opts) {
Bitmap bm = null;
InputStream stream = null;
try {
stream = new FileInputStream(pathName);
bm = decodeStream(stream, null, opts);
} catch (Exception e) {
/* do nothing.
If the exception happened on open, bm will be null.
*/
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// do nothing here
}
}
}
return bm;
}
/**
* Decode a file path into a bitmap. If the specified file name is null,
* or cannot be decoded into a bitmap, the function returns null.
*
* @param pathName complete path name for the file to be decoded.
* @return the resulting decoded bitmap, or null if it could not be decoded.
*/
public static Bitmap decodeFile(String pathName) {
return decodeFile(pathName, null);
}
/**
* Decode a new Bitmap from an InputStream. This InputStream was obtained from
* resources, which we pass to be able to scale the bitmap accordingly.
*/
public static Bitmap decodeResourceStream(Resources res, TypedValue value,
InputStream is, Rect pad, Options opts) {
if (opts == null) {
opts = new Options();
}
if (opts.inDensity == 0 && value != null) {
final int density = value.density;
if (density == TypedValue.DENSITY_DEFAULT) {
opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
} else if (density != TypedValue.DENSITY_NONE) {
opts.inDensity = density;
}
}
if (opts.inTargetDensity == 0 && res != null) {
opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
}
return decodeStream(is, pad, opts);
}
/**
* Synonym for opening the given resource and calling
* {@link #decodeResourceStream}.
*
* @param res The resources object containing the image data
* @param id The resource id of the image data
* @param opts null-ok; Options that control downsampling and whether the
* image should be completely decoded, or just is size returned.
* @return The decoded bitmap, or null if the image data could not be
* decoded, or, if opts is non-null, if opts requested only the
* size be returned (in opts.outWidth and opts.outHeight)
*/
public static Bitmap decodeResource(Resources res, int id, Options opts) {
Bitmap bm = null;
InputStream is = null;
try {
final TypedValue value = new TypedValue();
is = res.openRawResource(id, value);
bm = decodeResourceStream(res, value, is, null, opts);
} catch (Exception e) {
/* do nothing.
If the exception happened on open, bm will be null.
If it happened on close, bm is still valid.
*/
} finally {
try {
if (is != null) is.close();
} catch (IOException e) {
// Ignore
}
}
return bm;
}
/**
* Synonym for {@link #decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}
* will null Options.
*
* @param res The resources object containing the image data
* @param id The resource id of the image data
* @return The decoded bitmap, or null if the image could not be decode.
*/
public static Bitmap decodeResource(Resources res, int id) {
return decodeResource(res, id, null);
}
/**
* Decode an immutable bitmap from the specified byte array.
*
* @param data byte array of compressed image data
* @param offset offset into imageData for where the decoder should begin
* parsing.
* @param length the number of bytes, beginning at offset, to parse
* @param opts null-ok; Options that control downsampling and whether the
* image should be completely decoded, or just is size returned.
* @return The decoded bitmap, or null if the image data could not be
* decoded, or, if opts is non-null, if opts requested only the
* size be returned (in opts.outWidth and opts.outHeight)
*/
public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
if ((offset | length) < 0 || data.length < offset + length) {
throw new ArrayIndexOutOfBoundsException();
}
// FIXME: implement as needed, but it's unlikely that this is needed in the context of the bridge.
return null;
//return nativeDecodeByteArray(data, offset, length, opts);
}
/**
* Decode an immutable bitmap from the specified byte array.
*
* @param data byte array of compressed image data
* @param offset offset into imageData for where the decoder should begin
* parsing.
* @param length the number of bytes, beginning at offset, to parse
* @return The decoded bitmap, or null if the image could not be decode.
*/
public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
return decodeByteArray(data, offset, length, null);
}
/**
* Decode an input stream into a bitmap. If the input stream is null, or
* cannot be used to decode a bitmap, the function returns null.
* The stream's position will be where ever it was after the encoded data
* was read.
*
* @param is The input stream that holds the raw data to be decoded into a
* bitmap.
* @param outPadding If not null, return the padding rect for the bitmap if
* it exists, otherwise set padding to [-1,-1,-1,-1]. If
* no bitmap is returned (null) then padding is
* unchanged.
* @param opts null-ok; Options that control downsampling and whether the
* image should be completely decoded, or just is size returned.
* @return The decoded bitmap, or null if the image data could not be
* decoded, or, if opts is non-null, if opts requested only the
* size be returned (in opts.outWidth and opts.outHeight)
*/
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
// we don't throw in this case, thus allowing the caller to only check
// the cache, and not force the image to be decoded.
if (is == null) {
return null;
}
// we need mark/reset to work properly
if (!is.markSupported()) {
is = new BufferedInputStream(is, 16 * 1024);
}
// so we can call reset() if a given codec gives up after reading up to
// this many bytes. FIXME: need to find out from the codecs what this
// value should be.
is.mark(1024);
Bitmap bm;
if (is instanceof AssetManager.AssetInputStream) {
// FIXME: log this.
return null;
} else {
// pass some temp storage down to the native code. 1024 is made up,
// but should be large enough to avoid too many small calls back
// into is.read(...) This number is not related to the value passed
// to mark(...) above.
try {
bm = new Bitmap(is);
} catch (IOException e) {
return null;
}
}
return finishDecode(bm, outPadding, opts);
}
private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
if (bm == null || opts == null) {
return bm;
}
final int density = opts.inDensity;
if (density == 0) {
return bm;
}
bm.setDensity(density);
final int targetDensity = opts.inTargetDensity;
if (targetDensity == 0 || density == targetDensity
|| density == opts.inScreenDensity) {
return bm;
}
byte[] np = bm.getNinePatchChunk();
final boolean isNinePatch = false; //np != null && NinePatch.isNinePatchChunk(np);
if (opts.inScaled || isNinePatch) {
float scale = targetDensity / (float)density;
// TODO: This is very inefficient and should be done in native by Skia
final Bitmap oldBitmap = bm;
bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
(int) (bm.getHeight() * scale + 0.5f), true);
oldBitmap.recycle();
if (isNinePatch) {
//np = nativeScaleNinePatch(np, scale, outPadding);
bm.setNinePatchChunk(np);
}
bm.setDensity(targetDensity);
}
return bm;
}
/**
* Decode an input stream into a bitmap. If the input stream is null, or
* cannot be used to decode a bitmap, the function returns null.
* The stream's position will be where ever it was after the encoded data
* was read.
*
* @param is The input stream that holds the raw data to be decoded into a
* bitmap.
* @return The decoded bitmap, or null if the image data could not be
* decoded, or, if opts is non-null, if opts requested only the
* size be returned (in opts.outWidth and opts.outHeight)
*/
public static Bitmap decodeStream(InputStream is) {
return decodeStream(is, null, null);
}
/**
* Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
* return null. The position within the descriptor will not be changed when
* this returns, so the descriptor can be used again as-is.
*
* @param fd The file descriptor containing the bitmap data to decode
* @param outPadding If not null, return the padding rect for the bitmap if
* it exists, otherwise set padding to [-1,-1,-1,-1]. If
* no bitmap is returned (null) then padding is
* unchanged.
* @param opts null-ok; Options that control downsampling and whether the
* image should be completely decoded, or just is size returned.
* @return the decoded bitmap, or null
*/
public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
return null;
/* FIXME: implement as needed
try {
if (MemoryFile.isMemoryFile(fd)) {
int mappedlength = MemoryFile.getMappedSize(fd);
MemoryFile file = new MemoryFile(fd, mappedlength, "r");
InputStream is = file.getInputStream();
Bitmap bm = decodeStream(is, outPadding, opts);
return finishDecode(bm, outPadding, opts);
}
} catch (IOException ex) {
// invalid filedescriptor, no need to call nativeDecodeFileDescriptor()
return null;
}
//Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
//return finishDecode(bm, outPadding, opts);
*/
}
/**
* Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
* return null. The position within the descriptor will not be changed when
* this returns, so the descriptor can be used again as is.
*
* @param fd The file descriptor containing the bitmap data to decode
* @return the decoded bitmap, or null
*/
public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
return decodeFileDescriptor(fd, null, null);
}
}

View File

@@ -0,0 +1,167 @@
/*
* 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 android.graphics;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeResources.NinePatchInputStream;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.ninepatch.NinePatchChunk;
import com.android.resources.Density;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.BitmapFactory.Options;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
/**
* Delegate implementing the native methods of android.graphics.BitmapFactory
*
* Through the layoutlib_create tool, the original native methods of BitmapFactory have been
* replaced by calls to methods of the same name in this delegate class.
*
* Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
* around to map int to instance of the delegate.
*
*/
/*package*/ class BitmapFactory_Delegate {
// ------ Java delegates ------
@LayoutlibDelegate
/*package*/ static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
if (bm == null || opts == null) {
return bm;
}
final int density = opts.inDensity;
if (density == 0) {
return bm;
}
bm.setDensity(density);
final int targetDensity = opts.inTargetDensity;
if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
return bm;
}
byte[] np = bm.getNinePatchChunk();
final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
// DELEGATE CHANGE: never scale 9-patch
if (opts.inScaled && isNinePatch == false) {
float scale = targetDensity / (float)density;
// TODO: This is very inefficient and should be done in native by Skia
final Bitmap oldBitmap = bm;
bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
(int) (bm.getHeight() * scale + 0.5f), true);
oldBitmap.recycle();
if (isNinePatch) {
np = nativeScaleNinePatch(np, scale, outPadding);
bm.setNinePatchChunk(np);
}
bm.setDensity(targetDensity);
}
return bm;
}
// ------ Native Delegates ------
@LayoutlibDelegate
/*package*/ static void nativeSetDefaultConfig(int nativeConfig) {
// pass
}
@LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage,
Rect padding, Options opts) {
Bitmap bm = null;
Density density = Density.MEDIUM;
if (opts != null) {
density = Density.getEnum(opts.inDensity);
}
try {
if (is instanceof NinePatchInputStream) {
NinePatchInputStream npis = (NinePatchInputStream) is;
npis.disableFakeMarkSupport();
// load the bitmap as a nine patch
com.android.ninepatch.NinePatch ninePatch = com.android.ninepatch.NinePatch.load(
npis, true /*is9Patch*/, false /*convert*/);
// get the bitmap and chunk objects.
bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(), true /*isMutable*/,
density);
NinePatchChunk chunk = ninePatch.getChunk();
// put the chunk in the bitmap
bm.setNinePatchChunk(NinePatch_Delegate.serialize(chunk));
// read the padding
int[] paddingarray = chunk.getPadding();
padding.left = paddingarray[0];
padding.top = paddingarray[1];
padding.right = paddingarray[2];
padding.bottom = paddingarray[3];
} else {
// load the bitmap directly.
bm = Bitmap_Delegate.createBitmap(is, true, density);
}
} catch (IOException e) {
Bridge.getLog().error(null,"Failed to load image" , e, null);
}
return bm;
}
@LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
Rect padding, Options opts) {
opts.inBitmap = null;
return null;
}
@LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts) {
opts.inBitmap = null;
return null;
}
@LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset,
int length, Options opts) {
opts.inBitmap = null;
return null;
}
@LayoutlibDelegate
/*package*/ static byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad) {
// don't scale for now. This should not be called anyway since we re-implement
// BitmapFactory.finishDecode();
return chunk;
}
@LayoutlibDelegate
/*package*/ static boolean nativeIsSeekable(FileDescriptor fd) {
return true;
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright (C) 2008 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 android.graphics;
import java.awt.Paint;
public class BitmapShader extends Shader {
// we hold on just for the GC, since our native counterpart is using it
private final Bitmap mBitmap;
/**
* Call this to create a new shader that will draw with a bitmap.
*
* @param bitmap The bitmap to use inside the shader
* @param tileX The tiling mode for x to draw the bitmap in.
* @param tileY The tiling mode for y to draw the bitmap in.
*/
public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
mBitmap = bitmap;
}
//---------- Custom methods
public Bitmap getBitmap() {
return mBitmap;
}
@Override
Paint getJavaPaint() {
return null;
}
}

View File

@@ -0,0 +1,247 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Shader.TileMode;
/**
* Delegate implementing the native methods of android.graphics.BitmapShader
*
* Through the layoutlib_create tool, the original native methods of BitmapShader have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original BitmapShader class.
*
* Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
* as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
*
* @see Shader_Delegate
*
*/
public class BitmapShader_Delegate extends Shader_Delegate {
// ---- delegate data ----
private java.awt.Paint mJavaPaint;
// ---- Public Helper methods ----
@Override
public java.awt.Paint getJavaPaint() {
return mJavaPaint;
}
@Override
public boolean isSupported() {
return true;
}
@Override
public String getSupportMessage() {
// no message since isSupported returns true;
return null;
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate(int native_bitmap, int shaderTileModeX,
int shaderTileModeY) {
Bitmap_Delegate bitmap = Bitmap_Delegate.getDelegate(native_bitmap);
if (bitmap == null) {
return 0;
}
BitmapShader_Delegate newDelegate = new BitmapShader_Delegate(
bitmap.getImage(),
Shader_Delegate.getTileMode(shaderTileModeX),
Shader_Delegate.getTileMode(shaderTileModeY));
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static int nativePostCreate(int native_shader, int native_bitmap,
int shaderTileModeX, int shaderTileModeY) {
// pass, not needed.
return 0;
}
// ---- Private delegate/helper methods ----
private BitmapShader_Delegate(java.awt.image.BufferedImage image,
TileMode tileModeX, TileMode tileModeY) {
mJavaPaint = new BitmapShaderPaint(image, tileModeX, tileModeY);
}
private class BitmapShaderPaint implements java.awt.Paint {
private final java.awt.image.BufferedImage mImage;
private final TileMode mTileModeX;
private final TileMode mTileModeY;
BitmapShaderPaint(java.awt.image.BufferedImage image,
TileMode tileModeX, TileMode tileModeY) {
mImage = image;
mTileModeX = tileModeX;
mTileModeY = tileModeY;
}
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
java.awt.geom.Rectangle2D userBounds,
java.awt.geom.AffineTransform xform,
java.awt.RenderingHints hints) {
java.awt.geom.AffineTransform canvasMatrix;
try {
canvasMatrix = xform.createInverse();
} catch (java.awt.geom.NoninvertibleTransformException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
"Unable to inverse matrix in BitmapShader", e, null /*data*/);
canvasMatrix = new java.awt.geom.AffineTransform();
}
java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
try {
localMatrix = localMatrix.createInverse();
} catch (java.awt.geom.NoninvertibleTransformException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
"Unable to inverse matrix in BitmapShader", e, null /*data*/);
localMatrix = new java.awt.geom.AffineTransform();
}
return new BitmapShaderContext(canvasMatrix, localMatrix, colorModel);
}
private class BitmapShaderContext implements java.awt.PaintContext {
private final java.awt.geom.AffineTransform mCanvasMatrix;
private final java.awt.geom.AffineTransform mLocalMatrix;
private final java.awt.image.ColorModel mColorModel;
public BitmapShaderContext(
java.awt.geom.AffineTransform canvasMatrix,
java.awt.geom.AffineTransform localMatrix,
java.awt.image.ColorModel colorModel) {
mCanvasMatrix = canvasMatrix;
mLocalMatrix = localMatrix;
mColorModel = colorModel;
}
public void dispose() {
}
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
int[] data = new int[w*h];
int index = 0;
float[] pt1 = new float[2];
float[] pt2 = new float[2];
for (int iy = 0 ; iy < h ; iy++) {
for (int ix = 0 ; ix < w ; ix++) {
// handle the canvas transform
pt1[0] = x + ix;
pt1[1] = y + iy;
mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
// handle the local matrix.
pt1[0] = pt2[0];
pt1[1] = pt2[1];
mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
data[index++] = getColor(pt2[0], pt2[1]);
}
}
image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
return image.getRaster();
}
}
/**
* Returns a color for an arbitrary point.
*/
private int getColor(float fx, float fy) {
int x = getCoordinate(Math.round(fx), mImage.getWidth(), mTileModeX);
int y = getCoordinate(Math.round(fy), mImage.getHeight(), mTileModeY);
return mImage.getRGB(x, y);
}
private int getCoordinate(int i, int size, TileMode mode) {
if (i < 0) {
switch (mode) {
case CLAMP:
i = 0;
break;
case REPEAT:
i = size - 1 - (-i % size);
break;
case MIRROR:
// this is the same as the positive side, just make the value positive
// first.
i = -i;
int count = i / size;
i = i % size;
if ((count % 2) == 1) {
i = size - 1 - i;
}
break;
}
} else if (i >= size) {
switch (mode) {
case CLAMP:
i = size - 1;
break;
case REPEAT:
i = i % size;
break;
case MIRROR:
int count = i / size;
i = i % size;
if ((count % 2) == 1) {
i = size - 1 - i;
}
break;
}
}
return i;
}
public int getTransparency() {
return java.awt.Paint.TRANSLUCENT;
}
}
}

View File

@@ -0,0 +1,563 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.resources.Density;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.os.Parcel;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.Buffer;
import java.util.Arrays;
import javax.imageio.ImageIO;
/**
* Delegate implementing the native methods of android.graphics.Bitmap
*
* Through the layoutlib_create tool, the original native methods of Bitmap have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original Bitmap class.
*
* @see DelegateManager
*
*/
public final class Bitmap_Delegate {
// ---- delegate manager ----
private static final DelegateManager<Bitmap_Delegate> sManager =
new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class);
// ---- delegate helper data ----
// ---- delegate data ----
private final Config mConfig;
private BufferedImage mImage;
private boolean mHasAlpha = true;
private int mGenerationId = 0;
// ---- Public Helper methods ----
/**
* Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
*/
public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
return sManager.getDelegate(bitmap.mNativeBitmap);
}
/**
* Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
*/
public static Bitmap_Delegate getDelegate(int native_bitmap) {
return sManager.getDelegate(native_bitmap);
}
/**
* Creates and returns a {@link Bitmap} initialized with the given file content.
*
* @param input the file from which to read the bitmap content
* @param isMutable whether the bitmap is mutable
* @param density the density associated with the bitmap
*
* @see Bitmap#isMutable()
* @see Bitmap#getDensity()
*/
public static Bitmap createBitmap(File input, boolean isMutable, Density density)
throws IOException {
// create a delegate with the content of the file.
Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
return createBitmap(delegate, isMutable, density.getDpiValue());
}
/**
* Creates and returns a {@link Bitmap} initialized with the given stream content.
*
* @param input the stream from which to read the bitmap content
* @param isMutable whether the bitmap is mutable
* @param density the density associated with the bitmap
*
* @see Bitmap#isMutable()
* @see Bitmap#getDensity()
*/
public static Bitmap createBitmap(InputStream input, boolean isMutable, Density density)
throws IOException {
// create a delegate with the content of the stream.
Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
return createBitmap(delegate, isMutable, density.getDpiValue());
}
/**
* Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
*
* @param image the bitmap content
* @param isMutable whether the bitmap is mutable
* @param density the density associated with the bitmap
*
* @see Bitmap#isMutable()
* @see Bitmap#getDensity()
*/
public static Bitmap createBitmap(BufferedImage image, boolean isMutable,
Density density) throws IOException {
// create a delegate with the given image.
Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888);
return createBitmap(delegate, isMutable, density.getDpiValue());
}
/**
* Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
*/
public static BufferedImage getImage(Bitmap bitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
if (delegate == null) {
return null;
}
return delegate.mImage;
}
public static int getBufferedImageType(int nativeBitmapConfig) {
switch (Config.sConfigs[nativeBitmapConfig]) {
case ALPHA_8:
return BufferedImage.TYPE_INT_ARGB;
case RGB_565:
return BufferedImage.TYPE_INT_ARGB;
case ARGB_4444:
return BufferedImage.TYPE_INT_ARGB;
case ARGB_8888:
return BufferedImage.TYPE_INT_ARGB;
}
return BufferedImage.TYPE_INT_ARGB;
}
/**
* Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
*/
public BufferedImage getImage() {
return mImage;
}
/**
* Returns the Android bitmap config. Note that this not the config of the underlying
* Java2D bitmap.
*/
public Config getConfig() {
return mConfig;
}
/**
* Returns the hasAlpha rendering hint
* @return true if the bitmap alpha should be used at render time
*/
public boolean hasAlpha() {
return mHasAlpha && mConfig != Config.RGB_565;
}
/**
* Update the generationId.
*
* @see Bitmap#getGenerationId()
*/
public void change() {
mGenerationId++;
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
int height, int nativeConfig, boolean mutable) {
int imageType = getBufferedImageType(nativeConfig);
// create the image
BufferedImage image = new BufferedImage(width, height, imageType);
if (colors != null) {
image.setRGB(0, 0, width, height, colors, offset, stride);
}
// create a delegate with the content of the stream.
Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.sConfigs[nativeConfig]);
return createBitmap(delegate, mutable, Bitmap.getDefaultDensity());
}
@LayoutlibDelegate
/*package*/ static Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable) {
Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(srcBitmap);
if (srcBmpDelegate == null) {
return null;
}
BufferedImage srcImage = srcBmpDelegate.getImage();
int width = srcImage.getWidth();
int height = srcImage.getHeight();
int imageType = getBufferedImageType(nativeConfig);
// create the image
BufferedImage image = new BufferedImage(width, height, imageType);
// copy the source image into the image.
int[] argb = new int[width * height];
srcImage.getRGB(0, 0, width, height, argb, 0, width);
image.setRGB(0, 0, width, height, argb, 0, width);
// create a delegate with the content of the stream.
Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.sConfigs[nativeConfig]);
return createBitmap(delegate, isMutable, Bitmap.getDefaultDensity());
}
@LayoutlibDelegate
/*package*/ static void nativeDestructor(int nativeBitmap) {
sManager.removeJavaReferenceFor(nativeBitmap);
}
@LayoutlibDelegate
/*package*/ static void nativeRecycle(int nativeBitmap) {
sManager.removeJavaReferenceFor(nativeBitmap);
}
@LayoutlibDelegate
/*package*/ static boolean nativeCompress(int nativeBitmap, int format, int quality,
OutputStream stream, byte[] tempStorage) {
Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
"Bitmap.compress() is not supported", null /*data*/);
return true;
}
@LayoutlibDelegate
/*package*/ static void nativeErase(int nativeBitmap, int color) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return;
}
BufferedImage image = delegate.mImage;
Graphics2D g = image.createGraphics();
try {
g.setColor(new java.awt.Color(color, true));
g.fillRect(0, 0, image.getWidth(), image.getHeight());
} finally {
g.dispose();
}
}
@LayoutlibDelegate
/*package*/ static int nativeWidth(int nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return 0;
}
return delegate.mImage.getWidth();
}
@LayoutlibDelegate
/*package*/ static int nativeHeight(int nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return 0;
}
return delegate.mImage.getHeight();
}
@LayoutlibDelegate
/*package*/ static int nativeRowBytes(int nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return 0;
}
return delegate.mImage.getWidth();
}
@LayoutlibDelegate
/*package*/ static int nativeConfig(int nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return 0;
}
return delegate.mConfig.nativeInt;
}
@LayoutlibDelegate
/*package*/ static boolean nativeHasAlpha(int nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return true;
}
return delegate.mHasAlpha;
}
@LayoutlibDelegate
/*package*/ static int nativeGetPixel(int nativeBitmap, int x, int y) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return 0;
}
return delegate.mImage.getRGB(x, y);
}
@LayoutlibDelegate
/*package*/ static void nativeGetPixels(int nativeBitmap, int[] pixels, int offset,
int stride, int x, int y, int width, int height) {
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return;
}
delegate.getImage().getRGB(x, y, width, height, pixels, offset, stride);
}
@LayoutlibDelegate
/*package*/ static void nativeSetPixel(int nativeBitmap, int x, int y, int color) {
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return;
}
delegate.getImage().setRGB(x, y, color);
}
@LayoutlibDelegate
/*package*/ static void nativeSetPixels(int nativeBitmap, int[] colors, int offset,
int stride, int x, int y, int width, int height) {
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return;
}
delegate.getImage().setRGB(x, y, width, height, colors, offset, stride);
}
@LayoutlibDelegate
/*package*/ static void nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst) {
// FIXME implement native delegate
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Bitmap.copyPixelsToBuffer is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
/*package*/ static void nativeCopyPixelsFromBuffer(int nb, Buffer src) {
// FIXME implement native delegate
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Bitmap.copyPixelsFromBuffer is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
/*package*/ static int nativeGenerationId(int nativeBitmap) {
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return 0;
}
return delegate.mGenerationId;
}
@LayoutlibDelegate
/*package*/ static Bitmap nativeCreateFromParcel(Parcel p) {
// This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only
// used during aidl call so really this should not be called.
Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
"AIDL is not suppored, and therefore Bitmaps cannot be created from parcels.",
null /*data*/);
return null;
}
@LayoutlibDelegate
/*package*/ static boolean nativeWriteToParcel(int nativeBitmap, boolean isMutable,
int density, Parcel p) {
// This is only called when sending a bitmap through aidl, so really this should not
// be called.
Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
"AIDL is not suppored, and therefore Bitmaps cannot be written to parcels.",
null /*data*/);
return false;
}
@LayoutlibDelegate
/*package*/ static Bitmap nativeExtractAlpha(int nativeBitmap, int nativePaint,
int[] offsetXY) {
Bitmap_Delegate bitmap = sManager.getDelegate(nativeBitmap);
if (bitmap == null) {
return null;
}
// get the paint which can be null if nativePaint is 0.
Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
if (paint != null && paint.getMaskFilter() != null) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
"MaskFilter not supported in Bitmap.extractAlpha",
null, null /*data*/);
}
int alpha = paint != null ? paint.getAlpha() : 0xFF;
BufferedImage image = createCopy(bitmap.getImage(), BufferedImage.TYPE_INT_ARGB, alpha);
// create the delegate. The actual Bitmap config is only an alpha channel
Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ALPHA_8);
// the density doesn't matter, it's set by the Java method.
return createBitmap(delegate, false /*isMutable*/,
Density.DEFAULT_DENSITY /*density*/);
}
@LayoutlibDelegate
/*package*/ static void nativePrepareToDraw(int nativeBitmap) {
// nothing to be done here.
}
@LayoutlibDelegate
/*package*/ static void nativeSetHasAlpha(int nativeBitmap, boolean hasAlpha) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
return;
}
delegate.mHasAlpha = hasAlpha;
}
@LayoutlibDelegate
/*package*/ static boolean nativeSameAs(int nb0, int nb1) {
Bitmap_Delegate delegate1 = sManager.getDelegate(nb0);
if (delegate1 == null) {
return false;
}
Bitmap_Delegate delegate2 = sManager.getDelegate(nb1);
if (delegate2 == null) {
return false;
}
BufferedImage image1 = delegate1.getImage();
BufferedImage image2 = delegate2.getImage();
if (delegate1.mConfig != delegate2.mConfig ||
image1.getWidth() != image2.getWidth() ||
image1.getHeight() != image2.getHeight()) {
return false;
}
// get the internal data
int w = image1.getWidth();
int h = image2.getHeight();
int[] argb1 = new int[w*h];
int[] argb2 = new int[w*h];
image1.getRGB(0, 0, w, h, argb1, 0, w);
image2.getRGB(0, 0, w, h, argb2, 0, w);
// compares
if (delegate1.mConfig == Config.ALPHA_8) {
// in this case we have to manually compare the alpha channel as the rest is garbage.
final int length = w*h;
for (int i = 0 ; i < length ; i++) {
if ((argb1[i] & 0xFF000000) != (argb2[i] & 0xFF000000)) {
return false;
}
}
return true;
}
return Arrays.equals(argb1, argb2);
}
// ---- Private delegate/helper methods ----
private Bitmap_Delegate(BufferedImage image, Config config) {
mImage = image;
mConfig = config;
}
private static Bitmap createBitmap(Bitmap_Delegate delegate, boolean isMutable, int density) {
// get its native_int
int nativeInt = sManager.addNewDelegate(delegate);
// and create/return a new Bitmap with it
return new Bitmap(nativeInt, null /* buffer */, isMutable, null /*ninePatchChunk*/, density);
}
/**
* Creates and returns a copy of a given BufferedImage.
* <p/>
* if alpha is different than 255, then it is applied to the alpha channel of each pixel.
*
* @param image the image to copy
* @param imageType the type of the new image
* @param alpha an optional alpha modifier
* @return a new BufferedImage
*/
/*package*/ static BufferedImage createCopy(BufferedImage image, int imageType, int alpha) {
int w = image.getWidth();
int h = image.getHeight();
BufferedImage result = new BufferedImage(w, h, imageType);
int[] argb = new int[w * h];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
if (alpha != 255) {
final int length = argb.length;
for (int i = 0 ; i < length; i++) {
int a = (argb[i] >>> 24 * alpha) / 255;
argb[i] = (a << 24) | (argb[i] & 0x00FFFFFF);
}
}
result.setRGB(0, 0, w, h, argb, 0, w);
return result;
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.BlurMaskFilter
*
* Through the layoutlib_create tool, the original native methods of BlurMaskFilter have
* been replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original BlurMaskFilter class.
*
* Because this extends {@link MaskFilter_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the Shader classes will be added to the manager
* owned by {@link MaskFilter_Delegate}.
*
* @see MaskFilter_Delegate
*
*/
public class BlurMaskFilter_Delegate extends MaskFilter_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Blur Mask Filters are not supported.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeConstructor(float radius, int style) {
BlurMaskFilter_Delegate newDelegate = new BlurMaskFilter_Delegate();
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.ColorFilter
*
* Through the layoutlib_create tool, the original native methods of ColorFilter have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original ColorFilter class.
*
* This also serve as a base class for all ColorFilter delegate classes.
*
* @see DelegateManager
*
*/
public abstract class ColorFilter_Delegate {
// ---- delegate manager ----
protected static final DelegateManager<ColorFilter_Delegate> sManager =
new DelegateManager<ColorFilter_Delegate>(ColorFilter_Delegate.class);
// ---- delegate helper data ----
// ---- delegate data ----
// ---- Public Helper methods ----
public static ColorFilter_Delegate getDelegate(int nativeShader) {
return sManager.getDelegate(nativeShader);
}
public abstract boolean isSupported();
public abstract String getSupportMessage();
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static void finalizer(int native_instance, int nativeColorFilter) {
sManager.removeJavaReferenceFor(native_instance);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.ColorMatrixColorFilter
*
* Through the layoutlib_create tool, the original native methods of ColorMatrixColorFilter have
* been replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original ColorMatrixColorFilter class.
*
* Because this extends {@link ColorFilter_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the Shader classes will be added to the manager
* owned by {@link ColorFilter_Delegate}.
*
* @see ColorFilter_Delegate
*
*/
public class ColorMatrixColorFilter_Delegate extends ColorFilter_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "ColorMatrix Color Filters are not supported.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeColorMatrixFilter(float[] array) {
ColorMatrixColorFilter_Delegate newDelegate = new ColorMatrixColorFilter_Delegate();
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static int nColorMatrixFilter(int nativeFilter, float[] array) {
// pass
return 0;
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
/**
* Delegate implementing the native methods of android.graphics.ComposePathEffect
*
* Through the layoutlib_create tool, the original native methods of ComposePathEffect have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original ComposePathEffect class.
*
* Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
* as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
*
* @see PathEffect_Delegate
*
*/
public class ComposePathEffect_Delegate extends PathEffect_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public Stroke getStroke(Paint_Delegate paint) {
// FIXME
return null;
}
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Compose Path Effects are not supported in Layout Preview mode.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate(int outerpe, int innerpe) {
ComposePathEffect_Delegate newDelegate = new ComposePathEffect_Delegate();
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright (C) 2008 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 android.graphics;
import java.awt.Paint;
/** A subclass of shader that returns the composition of two other shaders, combined by
an {@link android.graphics.Xfermode} subclass.
*/
public class ComposeShader extends Shader {
/** Create a new compose shader, given shaders A, B, and a combining mode.
When the mode is applied, it will be given the result from shader A as its
"dst", and the result of from shader B as its "src".
@param shaderA The colors from this shader are seen as the "dst" by the mode
@param shaderB The colors from this shader are seen as the "src" by the mode
@param mode The mode that combines the colors from the two shaders. If mode
is null, then SRC_OVER is assumed.
*/
public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) {
// FIXME Implement shader
}
/** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
When the mode is applied, it will be given the result from shader A as its
"dst", and the result of from shader B as its "src".
@param shaderA The colors from this shader are seen as the "dst" by the mode
@param shaderB The colors from this shader are seen as the "src" by the mode
@param mode The PorterDuff mode that combines the colors from the two shaders.
*/
public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) {
// FIXME Implement shader
}
@Override
Paint getJavaPaint() {
return null;
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Paint;
/**
* Delegate implementing the native methods of android.graphics.ComposeShader
*
* Through the layoutlib_create tool, the original native methods of ComposeShader have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original ComposeShader class.
*
* Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
* as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
*
* @see Shader_Delegate
*
*/
public class ComposeShader_Delegate extends Shader_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public Paint getJavaPaint() {
// FIXME
return null;
}
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Compose Shaders are not supported in Layout Preview mode.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate1(int native_shaderA, int native_shaderB,
int native_mode) {
// FIXME not supported yet.
ComposeShader_Delegate newDelegate = new ComposeShader_Delegate();
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static int nativeCreate2(int native_shaderA, int native_shaderB,
int porterDuffMode) {
// FIXME not supported yet.
ComposeShader_Delegate newDelegate = new ComposeShader_Delegate();
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static int nativePostCreate1(int native_shader, int native_skiaShaderA,
int native_skiaShaderB, int native_mode) {
// pass, not needed.
return 0;
}
@LayoutlibDelegate
/*package*/ static int nativePostCreate2(int native_shader, int native_skiaShaderA,
int native_skiaShaderB, int porterDuffMode) {
// pass, not needed.
return 0;
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
/**
* Delegate implementing the native methods of android.graphics.CornerPathEffect
*
* Through the layoutlib_create tool, the original native methods of CornerPathEffect have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original CornerPathEffect class.
*
* Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
* as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
*
* @see PathEffect_Delegate
*
*/
public class CornerPathEffect_Delegate extends PathEffect_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public Stroke getStroke(Paint_Delegate paint) {
// FIXME
return null;
}
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Corner Path Effects are not supported in Layout Preview mode.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate(float radius) {
CornerPathEffect_Delegate newDelegate = new CornerPathEffect_Delegate();
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2010 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 android.graphics;
public class DashPathEffect extends PathEffect {
private final float[] mIntervals;
private final float mPhase;
/**
* The intervals array must contain an even number of entries (>=2), with
* the even indices specifying the "on" intervals, and the odd indices
* specifying the "off" intervals. phase is an offset into the intervals
* array (mod the sum of all of the intervals). The intervals array
* controls the length of the dashes. The paint's strokeWidth controls the
* thickness of the dashes.
* Note: this patheffect only affects drawing with the paint's style is set
* to STROKE or STROKE_AND_FILL. It is ignored if the drawing is done with
* style == FILL.
* @param intervals array of ON and OFF distances
* @param phase offset into the intervals array
*/
public DashPathEffect(float intervals[], float phase) {
if (intervals.length < 2) {
throw new ArrayIndexOutOfBoundsException();
}
mIntervals = intervals;
mPhase = phase;
}
public float[] getIntervals() {
return mIntervals;
}
public float getPhase() {
return mPhase;
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.BasicStroke;
import java.awt.Stroke;
/**
* Delegate implementing the native methods of android.graphics.DashPathEffect
*
* Through the layoutlib_create tool, the original native methods of DashPathEffect have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original DashPathEffect class.
*
* Because this extends {@link PathEffect_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
* {@link PathEffect_Delegate}.
*
* @see PathEffect_Delegate
*
*/
public final class DashPathEffect_Delegate extends PathEffect_Delegate {
// ---- delegate data ----
private final float[] mIntervals;
private final float mPhase;
// ---- Public Helper methods ----
@Override
public Stroke getStroke(Paint_Delegate paint) {
return new BasicStroke(
paint.getStrokeWidth(),
paint.getJavaCap(),
paint.getJavaJoin(),
paint.getJavaStrokeMiter(),
mIntervals,
mPhase);
}
@Override
public boolean isSupported() {
return true;
}
@Override
public String getSupportMessage() {
// no message since isSupported returns true;
return null;
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate(float intervals[], float phase) {
DashPathEffect_Delegate newDelegate = new DashPathEffect_Delegate(intervals, phase);
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
private DashPathEffect_Delegate(float intervals[], float phase) {
mIntervals = new float[intervals.length];
System.arraycopy(intervals, 0, mIntervals, 0, intervals.length);
mPhase = phase;
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
/**
* Delegate implementing the native methods of android.graphics.DiscretePathEffect
*
* Through the layoutlib_create tool, the original native methods of DiscretePathEffect have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original DiscretePathEffect class.
*
* Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
* as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
*
* @see PathEffect_Delegate
*
*/
public class DiscretePathEffect_Delegate extends PathEffect_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public Stroke getStroke(Paint_Delegate paint) {
// FIXME
return null;
}
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Discrete Path Effects are not supported in Layout Preview mode.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate(float length, float deviation) {
DiscretePathEffect_Delegate newDelegate = new DiscretePathEffect_Delegate();
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.DrawFilter
*
* Through the layoutlib_create tool, the original native methods of DrawFilter have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original DrawFilter class.
*
* This also serve as a base class for all DrawFilter delegate classes.
*
* @see DelegateManager
*
*/
public abstract class DrawFilter_Delegate {
// ---- delegate manager ----
protected static final DelegateManager<DrawFilter_Delegate> sManager =
new DelegateManager<DrawFilter_Delegate>(DrawFilter_Delegate.class);
// ---- delegate helper data ----
// ---- delegate data ----
// ---- Public Helper methods ----
public static DrawFilter_Delegate getDelegate(int nativeDrawFilter) {
return sManager.getDelegate(nativeDrawFilter);
}
public abstract boolean isSupported();
public abstract String getSupportMessage();
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static void nativeDestructor(int nativeDrawFilter) {
sManager.removeJavaReferenceFor(nativeDrawFilter);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.EmbossMaskFilter
*
* Through the layoutlib_create tool, the original native methods of EmbossMaskFilter have
* been replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original EmbossMaskFilter class.
*
* Because this extends {@link MaskFilter_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the Shader classes will be added to the manager
* owned by {@link MaskFilter_Delegate}.
*
* @see MaskFilter_Delegate
*
*/
public class EmbossMaskFilter_Delegate extends MaskFilter_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Emboss Mask Filters are not supported.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeConstructor(float[] direction, float ambient,
float specular, float blurRadius) {
EmbossMaskFilter_Delegate newDelegate = new EmbossMaskFilter_Delegate();
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -16,23 +16,28 @@
package android.graphics;
import android.graphics.Shader.TileMode;
/**
* Base class for Gradient shader. This is not a standard android class and is just used
* as a base class for the re-implemented gradient classes.
*
* It also provides a base class to handle common code between the different shaders'
* implementations of {@link java.awt.Paint}.
*
* @see LinearGradient
* @see RadialGradient
* @see SweepGradient
* Base class for true Gradient shader delegate.
*/
public abstract class GradientShader extends Shader {
public abstract class Gradient_Delegate extends Shader_Delegate {
protected final int[] mColors;
protected final float[] mPositions;
@Override
public boolean isSupported() {
// all gradient shaders are supported.
return true;
}
@Override
public String getSupportMessage() {
// all gradient shaders are supported, no need for a gradient support
return null;
}
/**
* Creates the base shader and do some basic test on the parameters.
*
@@ -41,7 +46,7 @@ public abstract class GradientShader extends Shader {
* corresponding color in the colors array. If this is null, the
* the colors are distributed evenly along the gradient line.
*/
protected GradientShader(int colors[], float positions[]) {
protected Gradient_Delegate(int colors[], float positions[]) {
if (colors.length < 2) {
throw new IllegalArgumentException("needs >= 2 number of colors");
}
@@ -90,7 +95,7 @@ public abstract class GradientShader extends Shader {
* Pre-computes the colors for the gradient. This must be called once before any call
* to {@link #getGradientColor(float)}
*/
protected synchronized void precomputeGradientColors() {
protected void precomputeGradientColors() {
if (mGradient == null) {
// actually create an array with an extra size, so that we can really go
// from 0 to SIZE (100%), or currentPos in the loop below will never equal 1.0
@@ -126,20 +131,23 @@ public abstract class GradientShader extends Shader {
pos = 0.f;
break;
case REPEAT:
// remove the integer part to stay in the [0,1] range
// careful: this is a negative value, so use ceil instead of floor
pos = pos - (float)Math.ceil(pos);
// remove the integer part to stay in the [0,1] range.
// we also need to invert the value from [-1,0] to [0, 1]
pos = pos - (float)Math.floor(pos);
break;
case MIRROR:
// this is the same as the positive side, just make the value positive
// first.
pos = Math.abs(pos);
// get the integer and the decimal part
// careful: this is a negative value, so use ceil instead of floor
int intPart = (int)Math.ceil(pos);
int intPart = (int)Math.floor(pos);
pos = pos - intPart;
// 0 -> -1 : mirrored order
// -1 -> -2: normal order
// 0 -> 1 : normal order
// 1 -> 2: mirrored
// etc..
// this means if the intpart is even we invert
if ((intPart % 2) == 0) {
// this means if the intpart is odd we invert
if ((intPart % 2) == 1) {
pos = 1.f - pos;
}
break;
@@ -199,7 +207,5 @@ public abstract class GradientShader extends Shader {
private int computeChannel(int c1, int c2, float percent) {
return c1 + (int)((percent * (c2-c1)) + .5);
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.LayerRasterizer
*
* Through the layoutlib_create tool, the original native methods of LayerRasterizer have
* been replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original LayerRasterizer class.
*
* Because this extends {@link Rasterizer_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the Shader classes will be added to the manager
* owned by {@link Rasterizer_Delegate}.
*
* @see Rasterizer_Delegate
*
*/
public class LayerRasterizer_Delegate extends Rasterizer_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Layer Rasterizers are not supported.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeConstructor() {
LayerRasterizer_Delegate newDelegate = new LayerRasterizer_Delegate();
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static void nativeAddLayer(int native_layer, int native_paint, float dx, float dy) {
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.LightingColorFilter
*
* Through the layoutlib_create tool, the original native methods of LightingColorFilter have
* been replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original LightingColorFilter class.
*
* Because this extends {@link ColorFilter_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the Shader classes will be added to the manager
* owned by {@link ColorFilter_Delegate}.
*
* @see ColorFilter_Delegate
*
*/
public class LightingColorFilter_Delegate extends ColorFilter_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Lighting Color Filters are not supported.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int native_CreateLightingFilter(int mul, int add) {
LightingColorFilter_Delegate newDelegate = new LightingColorFilter_Delegate();
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static int nCreateLightingFilter(int nativeFilter, int mul, int add) {
// pass
return 0;
}
// ---- Private delegate/helper methods ----
}

View File

@@ -1,173 +0,0 @@
/*
* Copyright (C) 2008 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 android.graphics;
public class LinearGradient extends GradientShader {
private java.awt.Paint mJavaPaint;
/**
* Create a shader that draws a linear gradient along a line.
*
* @param x0 The x-coordinate for the start of the gradient line
* @param y0 The y-coordinate for the start of the gradient line
* @param x1 The x-coordinate for the end of the gradient line
* @param y1 The y-coordinate for the end of the gradient line
* @param colors The colors to be distributed along the gradient line
* @param positions May be null. The relative positions [0..1] of each
* corresponding color in the colors array. If this is null, the
* the colors are distributed evenly along the gradient line.
* @param tile The Shader tiling mode
*/
public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
TileMode tile) {
super(colors, positions);
mJavaPaint = new LinearGradientPaint(x0, y0, x1, y1, mColors, mPositions, tile);
}
/**
* Create a shader that draws a linear gradient along a line.
*
* @param x0 The x-coordinate for the start of the gradient line
* @param y0 The y-coordinate for the start of the gradient line
* @param x1 The x-coordinate for the end of the gradient line
* @param y1 The y-coordinate for the end of the gradient line
* @param color0 The color at the start of the gradient line.
* @param color1 The color at the end of the gradient line.
* @param tile The Shader tiling mode
*/
public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
TileMode tile) {
this(x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/, tile);
}
// ---------- Custom Methods
@Override
java.awt.Paint getJavaPaint() {
return mJavaPaint;
}
/**
* Linear Gradient (Java) Paint able to handle more than 2 points, as
* {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile
* modes.
*/
private static class LinearGradientPaint extends GradientPaint {
private final float mX0;
private final float mY0;
private final float mDx;
private final float mDy;
private final float mDSize2;
public LinearGradientPaint(float x0, float y0, float x1, float y1, int colors[],
float positions[], TileMode tile) {
super(colors, positions, tile);
mX0 = x0;
mY0 = y0;
mDx = x1 - x0;
mDy = y1 - y0;
mDSize2 = mDx * mDx + mDy * mDy;
}
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
java.awt.geom.Rectangle2D userBounds,
java.awt.geom.AffineTransform xform,
java.awt.RenderingHints hints) {
precomputeGradientColors();
return new LinearGradientPaintContext(colorModel);
}
private class LinearGradientPaintContext implements java.awt.PaintContext {
private final java.awt.image.ColorModel mColorModel;
public LinearGradientPaintContext(java.awt.image.ColorModel colorModel) {
mColorModel = colorModel;
// FIXME: so far all this is always the same rect gotten in getRaster with an indentity matrix?
}
public void dispose() {
}
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
int[] data = new int[w*h];
if (mDx == 0) { // vertical gradient
// compute first column and copy to all other columns
int index = 0;
for (int iy = 0 ; iy < h ; iy++) {
int color = getColor(iy + y, mY0, mDy);
for (int ix = 0 ; ix < w ; ix++) {
data[index++] = color;
}
}
} else if (mDy == 0) { // horizontal
// compute first line in a tmp array and copy to all lines
int[] line = new int[w];
for (int ix = 0 ; ix < w ; ix++) {
line[ix] = getColor(ix + x, mX0, mDx);
}
for (int iy = 0 ; iy < h ; iy++) {
System.arraycopy(line, 0, data, iy*w, line.length);
}
} else {
int index = 0;
for (int iy = 0 ; iy < h ; iy++) {
for (int ix = 0 ; ix < w ; ix++) {
data[index++] = getColor(ix + x, iy + y);
}
}
}
image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
return image.getRaster();
}
}
/** Returns a color for the easy vertical/horizontal mode */
private int getColor(float absPos, float refPos, float refSize) {
float pos = (absPos - refPos) / refSize;
return getGradientColor(pos);
}
/**
* Returns a color for an arbitrary point.
*/
private int getColor(float x, float y) {
// find the x position on the gradient vector.
float _x = (mDx*mDy*(y-mY0) + mDy*mDy*mX0 + mDx*mDx*x) / mDSize2;
// from it get the position relative to the vector
float pos = (float) ((_x - mX0) / mDx);
return getGradientColor(pos);
}
}
}

View File

@@ -0,0 +1,236 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Shader.TileMode;
/**
* Delegate implementing the native methods of android.graphics.LinearGradient
*
* Through the layoutlib_create tool, the original native methods of LinearGradient have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original LinearGradient class.
*
* Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
* as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
*
* @see Shader_Delegate
*
*/
public final class LinearGradient_Delegate extends Gradient_Delegate {
// ---- delegate data ----
private java.awt.Paint mJavaPaint;
// ---- Public Helper methods ----
@Override
public java.awt.Paint getJavaPaint() {
return mJavaPaint;
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate1(LinearGradient thisGradient,
float x0, float y0, float x1, float y1,
int colors[], float positions[], int tileMode) {
LinearGradient_Delegate newDelegate = new LinearGradient_Delegate(x0, y0, x1, y1,
colors, positions, Shader_Delegate.getTileMode(tileMode));
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static int nativeCreate2(LinearGradient thisGradient,
float x0, float y0, float x1, float y1,
int color0, int color1, int tileMode) {
return nativeCreate1(thisGradient,
x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/,
tileMode);
}
@LayoutlibDelegate
/*package*/ static int nativePostCreate1(LinearGradient thisGradient,
int native_shader, float x0, float y0, float x1, float y1,
int colors[], float positions[], int tileMode) {
// nothing to be done here.
return 0;
}
@LayoutlibDelegate
/*package*/ static int nativePostCreate2(LinearGradient thisGradient,
int native_shader, float x0, float y0, float x1, float y1,
int color0, int color1, int tileMode) {
// nothing to be done here.
return 0;
}
// ---- Private delegate/helper methods ----
/**
* Create a shader that draws a linear gradient along a line.
*
* @param x0 The x-coordinate for the start of the gradient line
* @param y0 The y-coordinate for the start of the gradient line
* @param x1 The x-coordinate for the end of the gradient line
* @param y1 The y-coordinate for the end of the gradient line
* @param colors The colors to be distributed along the gradient line
* @param positions May be null. The relative positions [0..1] of each
* corresponding color in the colors array. If this is null, the
* the colors are distributed evenly along the gradient line.
* @param tile The Shader tiling mode
*/
private LinearGradient_Delegate(float x0, float y0, float x1, float y1,
int colors[], float positions[], TileMode tile) {
super(colors, positions);
mJavaPaint = new LinearGradientPaint(x0, y0, x1, y1, mColors, mPositions, tile);
}
// ---- Custom Java Paint ----
/**
* Linear Gradient (Java) Paint able to handle more than 2 points, as
* {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile
* modes.
*/
private class LinearGradientPaint extends GradientPaint {
private final float mX0;
private final float mY0;
private final float mDx;
private final float mDy;
private final float mDSize2;
public LinearGradientPaint(float x0, float y0, float x1, float y1, int colors[],
float positions[], TileMode tile) {
super(colors, positions, tile);
mX0 = x0;
mY0 = y0;
mDx = x1 - x0;
mDy = y1 - y0;
mDSize2 = mDx * mDx + mDy * mDy;
}
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
java.awt.geom.Rectangle2D userBounds,
java.awt.geom.AffineTransform xform,
java.awt.RenderingHints hints) {
precomputeGradientColors();
java.awt.geom.AffineTransform canvasMatrix;
try {
canvasMatrix = xform.createInverse();
} catch (java.awt.geom.NoninvertibleTransformException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
"Unable to inverse matrix in LinearGradient", e, null /*data*/);
canvasMatrix = new java.awt.geom.AffineTransform();
}
java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
try {
localMatrix = localMatrix.createInverse();
} catch (java.awt.geom.NoninvertibleTransformException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
"Unable to inverse matrix in LinearGradient", e, null /*data*/);
localMatrix = new java.awt.geom.AffineTransform();
}
return new LinearGradientPaintContext(canvasMatrix, localMatrix, colorModel);
}
private class LinearGradientPaintContext implements java.awt.PaintContext {
private final java.awt.geom.AffineTransform mCanvasMatrix;
private final java.awt.geom.AffineTransform mLocalMatrix;
private final java.awt.image.ColorModel mColorModel;
private LinearGradientPaintContext(
java.awt.geom.AffineTransform canvasMatrix,
java.awt.geom.AffineTransform localMatrix,
java.awt.image.ColorModel colorModel) {
mCanvasMatrix = canvasMatrix;
mLocalMatrix = localMatrix;
mColorModel = colorModel;
}
public void dispose() {
}
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
int[] data = new int[w*h];
int index = 0;
float[] pt1 = new float[2];
float[] pt2 = new float[2];
for (int iy = 0 ; iy < h ; iy++) {
for (int ix = 0 ; ix < w ; ix++) {
// handle the canvas transform
pt1[0] = x + ix;
pt1[1] = y + iy;
mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
// handle the local matrix.
pt1[0] = pt2[0];
pt1[1] = pt2[1];
mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
data[index++] = getColor(pt2[0], pt2[1]);
}
}
image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
return image.getRaster();
}
}
/**
* Returns a color for an arbitrary point.
*/
private int getColor(float x, float y) {
float pos;
if (mDx == 0) {
pos = (y - mY0) / mDy;
} else if (mDy == 0) {
pos = (x - mX0) / mDx;
} else {
// find the x position on the gradient vector.
float _x = (mDx*mDy*(y-mY0) + mDy*mDy*mX0 + mDx*mDx*x) / mDSize2;
// from it get the position relative to the vector
pos = (_x - mX0) / mDx;
}
return getGradientColor(pos);
}
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.MaskFilter
*
* Through the layoutlib_create tool, the original native methods of MaskFilter have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original MaskFilter class.
*
* This also serve as a base class for all MaskFilter delegate classes.
*
* @see DelegateManager
*
*/
public abstract class MaskFilter_Delegate {
// ---- delegate manager ----
protected static final DelegateManager<MaskFilter_Delegate> sManager =
new DelegateManager<MaskFilter_Delegate>(MaskFilter_Delegate.class);
// ---- delegate helper data ----
// ---- delegate data ----
// ---- Public Helper methods ----
public static MaskFilter_Delegate getDelegate(int nativeShader) {
return sManager.getDelegate(nativeShader);
}
public abstract boolean isSupported();
public abstract String getSupportMessage();
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static void nativeDestructor(int native_filter) {
sManager.removeJavaReferenceFor(native_filter);
}
// ---- Private delegate/helper methods ----
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,225 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.impl.GcSnapshot;
import com.android.ninepatch.NinePatchChunk;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.drawable.NinePatchDrawable;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
/**
* Delegate implementing the native methods of android.graphics.NinePatch
*
* Through the layoutlib_create tool, the original native methods of NinePatch have been replaced
* by calls to methods of the same name in this delegate class.
*
* Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
* around to map int to instance of the delegate.
*
*/
public final class NinePatch_Delegate {
/**
* Cache map for {@link NinePatchChunk}.
* When the chunks are created they are serialized into a byte[], and both are put
* in the cache, using a {@link SoftReference} for the chunk. The default Java classes
* for {@link NinePatch} and {@link NinePatchDrawable} only reference to the byte[] data, and
* provide this for drawing.
* Using the cache map allows us to not have to deserialize the byte[] back into a
* {@link NinePatchChunk} every time a rendering is done.
*/
private final static Map<byte[], SoftReference<NinePatchChunk>> sChunkCache =
new HashMap<byte[], SoftReference<NinePatchChunk>>();
// ---- Public Helper methods ----
/**
* Serializes the given chunk.
*
* @return the serialized data for the chunk.
*/
public static byte[] serialize(NinePatchChunk chunk) {
// serialize the chunk to get a byte[]
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(baos);
oos.writeObject(chunk);
} catch (IOException e) {
Bridge.getLog().error(null, "Failed to serialize NinePatchChunk.", e, null /*data*/);
return null;
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
}
}
}
// get the array and add it to the cache
byte[] array = baos.toByteArray();
sChunkCache.put(array, new SoftReference<NinePatchChunk>(chunk));
return array;
}
/**
* Returns a {@link NinePatchChunk} object for the given serialized representation.
*
* If the chunk is present in the cache then the object from the cache is returned, otherwise
* the array is deserialized into a {@link NinePatchChunk} object.
*
* @param array the serialized representation of the chunk.
* @return the NinePatchChunk or null if deserialization failed.
*/
public static NinePatchChunk getChunk(byte[] array) {
SoftReference<NinePatchChunk> chunkRef = sChunkCache.get(array);
NinePatchChunk chunk = chunkRef.get();
if (chunk == null) {
ByteArrayInputStream bais = new ByteArrayInputStream(array);
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(bais);
chunk = (NinePatchChunk) ois.readObject();
// put back the chunk in the cache
if (chunk != null) {
sChunkCache.put(array, new SoftReference<NinePatchChunk>(chunk));
}
} catch (IOException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
"Failed to deserialize NinePatchChunk content.", e, null /*data*/);
return null;
} catch (ClassNotFoundException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
"Failed to deserialize NinePatchChunk class.", e, null /*data*/);
return null;
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
}
}
}
}
return chunk;
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static boolean isNinePatchChunk(byte[] chunk) {
NinePatchChunk chunkObject = getChunk(chunk);
if (chunkObject != null) {
return true;
}
return false;
}
@LayoutlibDelegate
/*package*/ static void validateNinePatchChunk(int bitmap, byte[] chunk) {
// the default JNI implementation only checks that the byte[] has the same
// size as the C struct it represent. Since we cannot do the same check (serialization
// will return different size depending on content), we do nothing.
}
@LayoutlibDelegate
/*package*/ static void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) {
draw(canvas_instance,
(int) loc.left, (int) loc.top, (int) loc.width(), (int) loc.height(),
bitmap_instance, c, paint_instance_or_null,
destDensity, srcDensity);
}
@LayoutlibDelegate
/*package*/ static void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) {
draw(canvas_instance,
loc.left, loc.top, loc.width(), loc.height(),
bitmap_instance, c, paint_instance_or_null,
destDensity, srcDensity);
}
@LayoutlibDelegate
/*package*/ static int nativeGetTransparentRegion(int bitmap, byte[] chunk, Rect location) {
return 0;
}
// ---- Private Helper methods ----
private static void draw(int canvas_instance,
final int left, final int top, final int right, final int bottom,
int bitmap_instance, byte[] c, int paint_instance_or_null,
final int destDensity, final int srcDensity) {
// get the delegate from the native int.
final Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance);
if (bitmap_delegate == null) {
return;
}
if (c == null) {
// not a 9-patch?
BufferedImage image = bitmap_delegate.getImage();
Canvas_Delegate.native_drawBitmap(canvas_instance, bitmap_instance,
new Rect(0, 0, image.getWidth(), image.getHeight()),
new Rect(left, top, right, bottom),
paint_instance_or_null, destDensity, srcDensity);
return;
}
final NinePatchChunk chunkObject = getChunk(c);
assert chunkObject != null;
if (chunkObject == null) {
return;
}
Canvas_Delegate canvas_delegate = Canvas_Delegate.getDelegate(canvas_instance);
if (canvas_delegate == null) {
return;
}
// this one can be null
Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null);
canvas_delegate.getSnapshot().draw(new GcSnapshot.Drawable() {
public void draw(Graphics2D graphics, Paint_Delegate paint) {
chunkObject.draw(bitmap_delegate.getImage(), graphics,
left, top, right - left, bottom - top, destDensity, srcDensity);
}
}, paint_delegate, true /*compositeOnly*/, false /*forceSrcMode*/);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.PaintFlagsDrawFilter
*
* Through the layoutlib_create tool, the original native methods of PaintFlagsDrawFilter have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original PaintFlagsDrawFilter class.
*
* Because this extends {@link DrawFilter_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the DrawFilter classes will be added to the manager owned by
* {@link DrawFilter_Delegate}.
*
* @see DrawFilter_Delegate
*
*/
public class PaintFlagsDrawFilter_Delegate extends DrawFilter_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Paint Flags Draw Filters are not supported.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeConstructor(int clearBits, int setBits) {
PaintFlagsDrawFilter_Delegate newDelegate = new PaintFlagsDrawFilter_Delegate();
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,611 +0,0 @@
/*
* Copyright (C) 2006 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 android.graphics;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
/**
* The Path class encapsulates compound (multiple contour) geometric paths
* consisting of straight line segments, quadratic curves, and cubic curves.
* It can be drawn with canvas.drawPath(path, paint), either filled or stroked
* (based on the paint's Style), or it can be used for clipping or to draw
* text on a path.
*/
public class Path {
private FillType mFillType = FillType.WINDING;
private GeneralPath mPath = new GeneralPath();
private float mLastX = 0;
private float mLastY = 0;
//---------- Custom methods ----------
public Shape getAwtShape() {
return mPath;
}
//----------
/**
* Create an empty path
*/
public Path() {
}
/**
* Create a new path, copying the contents from the src path.
*
* @param src The path to copy from when initializing the new path
*/
public Path(Path src) {
mPath.append(src.mPath, false /* connect */);
}
/**
* Clear any lines and curves from the path, making it empty.
* This does NOT change the fill-type setting.
*/
public void reset() {
mPath = new GeneralPath();
}
/**
* Rewinds the path: clears any lines and curves from the path but
* keeps the internal data structure for faster reuse.
*/
public void rewind() {
// FIXME
throw new UnsupportedOperationException();
}
/** Replace the contents of this with the contents of src.
*/
public void set(Path src) {
mPath.append(src.mPath, false /* connect */);
}
/** Enum for the ways a path may be filled
*/
public enum FillType {
// these must match the values in SkPath.h
WINDING (GeneralPath.WIND_NON_ZERO, false),
EVEN_ODD (GeneralPath.WIND_EVEN_ODD, false),
INVERSE_WINDING (GeneralPath.WIND_NON_ZERO, true),
INVERSE_EVEN_ODD(GeneralPath.WIND_EVEN_ODD, true);
FillType(int rule, boolean inverse) {
this.rule = rule;
this.inverse = inverse;
}
final int rule;
final boolean inverse;
}
/**
* Return the path's fill type. This defines how "inside" is
* computed. The default value is WINDING.
*
* @return the path's fill type
*/
public FillType getFillType() {
return mFillType;
}
/**
* Set the path's fill type. This defines how "inside" is computed.
*
* @param ft The new fill type for this path
*/
public void setFillType(FillType ft) {
mFillType = ft;
mPath.setWindingRule(ft.rule);
}
/**
* Returns true if the filltype is one of the INVERSE variants
*
* @return true if the filltype is one of the INVERSE variants
*/
public boolean isInverseFillType() {
return mFillType.inverse;
}
/**
* Toggles the INVERSE state of the filltype
*/
public void toggleInverseFillType() {
switch (mFillType) {
case WINDING:
mFillType = FillType.INVERSE_WINDING;
break;
case EVEN_ODD:
mFillType = FillType.INVERSE_EVEN_ODD;
break;
case INVERSE_WINDING:
mFillType = FillType.WINDING;
break;
case INVERSE_EVEN_ODD:
mFillType = FillType.EVEN_ODD;
break;
}
}
/**
* Returns true if the path is empty (contains no lines or curves)
*
* @return true if the path is empty (contains no lines or curves)
*/
public boolean isEmpty() {
return mPath.getCurrentPoint() == null;
}
/**
* Returns true if the path specifies a rectangle. If so, and if rect is
* not null, set rect to the bounds of the path. If the path does not
* specify a rectangle, return false and ignore rect.
*
* @param rect If not null, returns the bounds of the path if it specifies
* a rectangle
* @return true if the path specifies a rectangle
*/
public boolean isRect(RectF rect) {
// FIXME
throw new UnsupportedOperationException();
}
/**
* Compute the bounds of the path, and write the answer into bounds. If the
* path contains 0 or 1 points, the bounds is set to (0,0,0,0)
*
* @param bounds Returns the computed bounds of the path
* @param exact If true, return the exact (but slower) bounds, else return
* just the bounds of all control points
*/
public void computeBounds(RectF bounds, boolean exact) {
Rectangle2D rect = mPath.getBounds2D();
bounds.left = (float)rect.getMinX();
bounds.right = (float)rect.getMaxX();
bounds.top = (float)rect.getMinY();
bounds.bottom = (float)rect.getMaxY();
}
/**
* Hint to the path to prepare for adding more points. This can allow the
* path to more efficiently allocate its storage.
*
* @param extraPtCount The number of extra points that may be added to this
* path
*/
public void incReserve(int extraPtCount) {
// pass
}
/**
* Set the beginning of the next contour to the point (x,y).
*
* @param x The x-coordinate of the start of a new contour
* @param y The y-coordinate of the start of a new contour
*/
public void moveTo(float x, float y) {
mPath.moveTo(mLastX = x, mLastY = y);
}
/**
* Set the beginning of the next contour relative to the last point on the
* previous contour. If there is no previous contour, this is treated the
* same as moveTo().
*
* @param dx The amount to add to the x-coordinate of the end of the
* previous contour, to specify the start of a new contour
* @param dy The amount to add to the y-coordinate of the end of the
* previous contour, to specify the start of a new contour
*/
public void rMoveTo(float dx, float dy) {
dx += mLastX;
dy += mLastY;
mPath.moveTo(mLastX = dx, mLastY = dy);
}
/**
* Add a line from the last point to the specified point (x,y).
* If no moveTo() call has been made for this contour, the first point is
* automatically set to (0,0).
*
* @param x The x-coordinate of the end of a line
* @param y The y-coordinate of the end of a line
*/
public void lineTo(float x, float y) {
mPath.lineTo(mLastX = x, mLastY = y);
}
/**
* Same as lineTo, but the coordinates are considered relative to the last
* point on this contour. If there is no previous point, then a moveTo(0,0)
* is inserted automatically.
*
* @param dx The amount to add to the x-coordinate of the previous point on
* this contour, to specify a line
* @param dy The amount to add to the y-coordinate of the previous point on
* this contour, to specify a line
*/
public void rLineTo(float dx, float dy) {
if (isEmpty()) {
mPath.moveTo(mLastX = 0, mLastY = 0);
}
dx += mLastX;
dy += mLastY;
mPath.lineTo(mLastX = dx, mLastY = dy);
}
/**
* Add a quadratic bezier from the last point, approaching control point
* (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
* this contour, the first point is automatically set to (0,0).
*
* @param x1 The x-coordinate of the control point on a quadratic curve
* @param y1 The y-coordinate of the control point on a quadratic curve
* @param x2 The x-coordinate of the end point on a quadratic curve
* @param y2 The y-coordinate of the end point on a quadratic curve
*/
public void quadTo(float x1, float y1, float x2, float y2) {
mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2);
}
/**
* Same as quadTo, but the coordinates are considered relative to the last
* point on this contour. If there is no previous point, then a moveTo(0,0)
* is inserted automatically.
*
* @param dx1 The amount to add to the x-coordinate of the last point on
* this contour, for the control point of a quadratic curve
* @param dy1 The amount to add to the y-coordinate of the last point on
* this contour, for the control point of a quadratic curve
* @param dx2 The amount to add to the x-coordinate of the last point on
* this contour, for the end point of a quadratic curve
* @param dy2 The amount to add to the y-coordinate of the last point on
* this contour, for the end point of a quadratic curve
*/
public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
if (isEmpty()) {
mPath.moveTo(mLastX = 0, mLastY = 0);
}
dx1 += mLastX;
dy1 += mLastY;
dx2 += mLastX;
dy2 += mLastY;
mPath.quadTo(dx1, dy1, mLastX = dx2, mLastY = dy2);
}
/**
* Add a cubic bezier from the last point, approaching control points
* (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
* made for this contour, the first point is automatically set to (0,0).
*
* @param x1 The x-coordinate of the 1st control point on a cubic curve
* @param y1 The y-coordinate of the 1st control point on a cubic curve
* @param x2 The x-coordinate of the 2nd control point on a cubic curve
* @param y2 The y-coordinate of the 2nd control point on a cubic curve
* @param x3 The x-coordinate of the end point on a cubic curve
* @param y3 The y-coordinate of the end point on a cubic curve
*/
public void cubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3);
}
/**
* Same as cubicTo, but the coordinates are considered relative to the
* current point on this contour. If there is no previous point, then a
* moveTo(0,0) is inserted automatically.
*/
public void rCubicTo(float dx1, float dy1, float dx2, float dy2,
float dx3, float dy3) {
if (isEmpty()) {
mPath.moveTo(mLastX = 0, mLastY = 0);
}
dx1 += mLastX;
dy1 += mLastY;
dx2 += mLastX;
dy2 += mLastY;
dx3 += mLastX;
dy3 += mLastY;
mPath.curveTo(dx1, dy1, dx2, dy2, mLastX = dx3, mLastY = dy3);
}
/**
* Append the specified arc to the path as a new contour. If the start of
* the path is different from the path's current last point, then an
* automatic lineTo() is added to connect the current contour to the
* start of the arc. However, if the path is empty, then we call moveTo()
* with the first point of the arc. The sweep angle is tread mod 360.
*
* @param oval The bounds of oval defining shape and size of the arc
* @param startAngle Starting angle (in degrees) where the arc begins
* @param sweepAngle Sweep angle (in degrees) measured clockwise, treated
* mod 360.
* @param forceMoveTo If true, always begin a new contour with the arc
*/
public void arcTo(RectF oval, float startAngle, float sweepAngle,
boolean forceMoveTo) {
throw new UnsupportedOperationException();
}
/**
* Append the specified arc to the path as a new contour. If the start of
* the path is different from the path's current last point, then an
* automatic lineTo() is added to connect the current contour to the
* start of the arc. However, if the path is empty, then we call moveTo()
* with the first point of the arc.
*
* @param oval The bounds of oval defining shape and size of the arc
* @param startAngle Starting angle (in degrees) where the arc begins
* @param sweepAngle Sweep angle (in degrees) measured clockwise
*/
public void arcTo(RectF oval, float startAngle, float sweepAngle) {
throw new UnsupportedOperationException();
}
/**
* Close the current contour. If the current point is not equal to the
* first point of the contour, a line segment is automatically added.
*/
public void close() {
mPath.closePath();
}
/**
* Specifies how closed shapes (e.g. rects, ovals) are oriented when they
* are added to a path.
*/
public enum Direction {
/** clockwise */
CW (0), // must match enum in SkPath.h
/** counter-clockwise */
CCW (1); // must match enum in SkPath.h
Direction(int ni) {
nativeInt = ni;
}
final int nativeInt;
}
/**
* Add a closed rectangle contour to the path
*
* @param rect The rectangle to add as a closed contour to the path
* @param dir The direction to wind the rectangle's contour
*/
public void addRect(RectF rect, Direction dir) {
if (rect == null) {
throw new NullPointerException("need rect parameter");
}
addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
}
/**
* Add a closed rectangle contour to the path
*
* @param left The left side of a rectangle to add to the path
* @param top The top of a rectangle to add to the path
* @param right The right side of a rectangle to add to the path
* @param bottom The bottom of a rectangle to add to the path
* @param dir The direction to wind the rectangle's contour
*/
public void addRect(float left, float top, float right, float bottom,
Direction dir) {
moveTo(left, top);
switch (dir) {
case CW:
lineTo(right, top);
lineTo(right, bottom);
lineTo(left, bottom);
break;
case CCW:
lineTo(left, bottom);
lineTo(right, bottom);
lineTo(right, top);
break;
}
close();
}
/**
* Add a closed oval contour to the path
*
* @param oval The bounds of the oval to add as a closed contour to the path
* @param dir The direction to wind the oval's contour
*/
public void addOval(RectF oval, Direction dir) {
if (oval == null) {
throw new NullPointerException("need oval parameter");
}
// FIXME Need to support direction
Ellipse2D ovalShape = new Ellipse2D.Float(oval.left, oval.top, oval.width(), oval.height());
mPath.append(ovalShape, false /* connect */);
}
/**
* Add a closed circle contour to the path
*
* @param x The x-coordinate of the center of a circle to add to the path
* @param y The y-coordinate of the center of a circle to add to the path
* @param radius The radius of a circle to add to the path
* @param dir The direction to wind the circle's contour
*/
public void addCircle(float x, float y, float radius, Direction dir) {
// FIXME
throw new UnsupportedOperationException();
}
/**
* Add the specified arc to the path as a new contour.
*
* @param oval The bounds of oval defining the shape and size of the arc
* @param startAngle Starting angle (in degrees) where the arc begins
* @param sweepAngle Sweep angle (in degrees) measured clockwise
*/
public void addArc(RectF oval, float startAngle, float sweepAngle) {
if (oval == null) {
throw new NullPointerException("need oval parameter");
}
// FIXME
throw new UnsupportedOperationException();
}
/**
* Add a closed round-rectangle contour to the path
*
* @param rect The bounds of a round-rectangle to add to the path
* @param rx The x-radius of the rounded corners on the round-rectangle
* @param ry The y-radius of the rounded corners on the round-rectangle
* @param dir The direction to wind the round-rectangle's contour
*/
public void addRoundRect(RectF rect, float rx, float ry, Direction dir) {
if (rect == null) {
throw new NullPointerException("need rect parameter");
}
// FIXME
throw new UnsupportedOperationException();
}
/**
* Add a closed round-rectangle contour to the path. Each corner receives
* two radius values [X, Y]. The corners are ordered top-left, top-right,
* bottom-right, bottom-left
*
* @param rect The bounds of a round-rectangle to add to the path
* @param radii Array of 8 values, 4 pairs of [X,Y] radii
* @param dir The direction to wind the round-rectangle's contour
*/
public void addRoundRect(RectF rect, float[] radii, Direction dir) {
if (rect == null) {
throw new NullPointerException("need rect parameter");
}
if (radii.length < 8) {
throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
}
// FIXME
throw new UnsupportedOperationException();
}
/**
* Add a copy of src to the path, offset by (dx,dy)
*
* @param src The path to add as a new contour
* @param dx The amount to translate the path in X as it is added
*/
public void addPath(Path src, float dx, float dy) {
PathIterator iterator = src.mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
mPath.append(iterator, false /* connect */);
}
/**
* Add a copy of src to the path
*
* @param src The path that is appended to the current path
*/
public void addPath(Path src) {
addPath(src, 0, 0);
}
/**
* Add a copy of src to the path, transformed by matrix
*
* @param src The path to add as a new contour
*/
public void addPath(Path src, Matrix matrix) {
// FIXME
throw new UnsupportedOperationException();
}
/**
* Offset the path by (dx,dy), returning true on success
*
* @param dx The amount in the X direction to offset the entire path
* @param dy The amount in the Y direction to offset the entire path
* @param dst The translated path is written here. If this is null, then
* the original path is modified.
*/
public void offset(float dx, float dy, Path dst) {
GeneralPath newPath = new GeneralPath();
PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
newPath.append(iterator, false /* connect */);
if (dst != null) {
dst.mPath = newPath;
} else {
mPath = newPath;
}
}
/**
* Offset the path by (dx,dy), returning true on success
*
* @param dx The amount in the X direction to offset the entire path
* @param dy The amount in the Y direction to offset the entire path
*/
public void offset(float dx, float dy) {
offset(dx, dy, null /* dst */);
}
/**
* Sets the last point of the path.
*
* @param dx The new X coordinate for the last point
* @param dy The new Y coordinate for the last point
*/
public void setLastPoint(float dx, float dy) {
mLastX = dx;
mLastY = dy;
}
/**
* Transform the points in this path by matrix, and write the answer
* into dst. If dst is null, then the the original path is modified.
*
* @param matrix The matrix to apply to the path
* @param dst The transformed path is written here. If dst is null,
* then the the original path is modified
*/
public void transform(Matrix matrix, Path dst) {
// FIXME
throw new UnsupportedOperationException();
}
/**
* Transform the points in this path by matrix.
*
* @param matrix The matrix to apply to the path
*/
public void transform(Matrix matrix) {
transform(matrix, null /* dst */);
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
/**
* Delegate implementing the native methods of android.graphics.PathDashPathEffect
*
* Through the layoutlib_create tool, the original native methods of PathDashPathEffect have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original PathDashPathEffect class.
*
* Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
* as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
*
* @see PathEffect_Delegate
*
*/
public class PathDashPathEffect_Delegate extends PathEffect_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public Stroke getStroke(Paint_Delegate paint) {
// FIXME
return null;
}
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Path Dash Path Effects are not supported in Layout Preview mode.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate(int native_path, float advance, float phase,
int native_style) {
PathDashPathEffect_Delegate newDelegate = new PathDashPathEffect_Delegate();
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
/**
* Delegate implementing the native methods of android.graphics.PathEffect
*
* Through the layoutlib_create tool, the original native methods of PathEffect have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original PathEffect class.
*
* This also serve as a base class for all PathEffect delegate classes.
*
* @see DelegateManager
*
*/
public abstract class PathEffect_Delegate {
// ---- delegate manager ----
protected static final DelegateManager<PathEffect_Delegate> sManager =
new DelegateManager<PathEffect_Delegate>(PathEffect_Delegate.class);
// ---- delegate helper data ----
// ---- delegate data ----
// ---- Public Helper methods ----
public static PathEffect_Delegate getDelegate(int nativeShader) {
return sManager.getDelegate(nativeShader);
}
public abstract Stroke getStroke(Paint_Delegate paint);
public abstract boolean isSupported();
public abstract String getSupportMessage();
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static void nativeDestructor(int native_patheffect) {
sManager.removeJavaReferenceFor(native_patheffect);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,761 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Path.Direction;
import android.graphics.Path.FillType;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* Delegate implementing the native methods of android.graphics.Path
*
* Through the layoutlib_create tool, the original native methods of Path have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original Path class.
*
* @see DelegateManager
*
*/
public final class Path_Delegate {
// ---- delegate manager ----
private static final DelegateManager<Path_Delegate> sManager =
new DelegateManager<Path_Delegate>(Path_Delegate.class);
// ---- delegate data ----
private FillType mFillType = FillType.WINDING;
private GeneralPath mPath = new GeneralPath();
private float mLastX = 0;
private float mLastY = 0;
// ---- Public Helper methods ----
public static Path_Delegate getDelegate(int nPath) {
return sManager.getDelegate(nPath);
}
public Shape getJavaShape() {
return mPath;
}
public void setJavaShape(Shape shape) {
mPath.reset();
mPath.append(shape, false /*connect*/);
}
public void reset() {
mPath.reset();
}
public void setPathIterator(PathIterator iterator) {
mPath.reset();
mPath.append(iterator, false /*connect*/);
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int init1() {
// create the delegate
Path_Delegate newDelegate = new Path_Delegate();
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static int init2(int nPath) {
// create the delegate
Path_Delegate newDelegate = new Path_Delegate();
// get the delegate to copy, which could be null if nPath is 0
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate != null) {
newDelegate.set(pathDelegate);
}
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static void native_reset(int nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.mPath.reset();
}
@LayoutlibDelegate
/*package*/ static void native_rewind(int nPath) {
// call out to reset since there's nothing to optimize in
// terms of data structs.
native_reset(nPath);
}
@LayoutlibDelegate
/*package*/ static void native_set(int native_dst, int native_src) {
Path_Delegate pathDstDelegate = sManager.getDelegate(native_dst);
if (pathDstDelegate == null) {
return;
}
Path_Delegate pathSrcDelegate = sManager.getDelegate(native_src);
if (pathSrcDelegate == null) {
return;
}
pathDstDelegate.set(pathSrcDelegate);
}
@LayoutlibDelegate
/*package*/ static int native_getFillType(int nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return 0;
}
return pathDelegate.mFillType.nativeInt;
}
@LayoutlibDelegate
/*package*/ static void native_setFillType(int nPath, int ft) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.mFillType = Path.sFillTypeArray[ft];
}
@LayoutlibDelegate
/*package*/ static boolean native_isEmpty(int nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return true;
}
return pathDelegate.isEmpty();
}
@LayoutlibDelegate
/*package*/ static boolean native_isRect(int nPath, RectF rect) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return false;
}
// create an Area that can test if the path is a rect
Area area = new Area(pathDelegate.mPath);
if (area.isRectangular()) {
if (rect != null) {
pathDelegate.fillBounds(rect);
}
return true;
}
return false;
}
@LayoutlibDelegate
/*package*/ static void native_computeBounds(int nPath, RectF bounds) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.fillBounds(bounds);
}
@LayoutlibDelegate
/*package*/ static void native_incReserve(int nPath, int extraPtCount) {
// since we use a java2D path, there's no way to pre-allocate new points,
// so we do nothing.
}
@LayoutlibDelegate
/*package*/ static void native_moveTo(int nPath, float x, float y) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.moveTo(x, y);
}
@LayoutlibDelegate
/*package*/ static void native_rMoveTo(int nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.rMoveTo(dx, dy);
}
@LayoutlibDelegate
/*package*/ static void native_lineTo(int nPath, float x, float y) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.lineTo(x, y);
}
@LayoutlibDelegate
/*package*/ static void native_rLineTo(int nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.rLineTo(dx, dy);
}
@LayoutlibDelegate
/*package*/ static void native_quadTo(int nPath, float x1, float y1, float x2, float y2) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.quadTo(x1, y1, x2, y2);
}
@LayoutlibDelegate
/*package*/ static void native_rQuadTo(int nPath, float dx1, float dy1, float dx2, float dy2) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.rQuadTo(dx1, dy1, dx2, dy2);
}
@LayoutlibDelegate
/*package*/ static void native_cubicTo(int nPath, float x1, float y1,
float x2, float y2, float x3, float y3) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.cubicTo(x1, y1, x2, y2, x3, y3);
}
@LayoutlibDelegate
/*package*/ static void native_rCubicTo(int nPath, float x1, float y1,
float x2, float y2, float x3, float y3) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.rCubicTo(x1, y1, x2, y2, x3, y3);
}
@LayoutlibDelegate
/*package*/ static void native_arcTo(int nPath, RectF oval,
float startAngle, float sweepAngle, boolean forceMoveTo) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
}
@LayoutlibDelegate
/*package*/ static void native_close(int nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.close();
}
@LayoutlibDelegate
/*package*/ static void native_addRect(int nPath, RectF rect, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
}
@LayoutlibDelegate
/*package*/ static void native_addRect(int nPath,
float left, float top, float right, float bottom, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.addRect(left, top, right, bottom, dir);
}
@LayoutlibDelegate
/*package*/ static void native_addOval(int nPath, RectF oval, int dir) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Path.addOval is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
/*package*/ static void native_addCircle(int nPath, float x, float y, float radius, int dir) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Path.addCircle is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
/*package*/ static void native_addArc(int nPath, RectF oval,
float startAngle, float sweepAngle) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Path.addArc is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
/*package*/ static void native_addRoundRect(int nPath, RectF rect,
float rx, float ry, int dir) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Path.addRoundRect is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
/*package*/ static void native_addRoundRect(int nPath, RectF r, float[] radii, int dir) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Path.addRoundRect is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
/*package*/ static void native_addPath(int nPath, int src, float dx, float dy) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Path.addPath is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
/*package*/ static void native_addPath(int nPath, int src) {
native_addPath(nPath, src, 0, 0);
}
@LayoutlibDelegate
/*package*/ static void native_addPath(int nPath, int src, int matrix) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Path.addPath is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
/*package*/ static void native_offset(int nPath, float dx, float dy, int dst_path) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
// could be null if the int is 0;
Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
pathDelegate.offset(dx, dy, dstDelegate);
}
@LayoutlibDelegate
/*package*/ static void native_offset(int nPath, float dx, float dy) {
native_offset(nPath, dx, dy, 0);
}
@LayoutlibDelegate
/*package*/ static void native_setLastPoint(int nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.mLastX = dx;
pathDelegate.mLastY = dy;
}
@LayoutlibDelegate
/*package*/ static void native_transform(int nPath, int matrix,
int dst_path) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
if (matrixDelegate == null) {
return;
}
// this can be null if dst_path is 0
Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
pathDelegate.transform(matrixDelegate, dstDelegate);
}
@LayoutlibDelegate
/*package*/ static void native_transform(int nPath, int matrix) {
native_transform(nPath, matrix, 0);
}
@LayoutlibDelegate
/*package*/ static void finalizer(int nPath) {
sManager.removeJavaReferenceFor(nPath);
}
// ---- Private helper methods ----
private void set(Path_Delegate delegate) {
mPath.reset();
setFillType(delegate.mFillType);
mPath.append(delegate.mPath, false /*connect*/);
}
private void setFillType(FillType fillType) {
mFillType = fillType;
mPath.setWindingRule(getWindingRule(fillType));
}
/**
* Returns the Java2D winding rules matching a given Android {@link FillType}.
* @param type the android fill type
* @return the matching java2d winding rule.
*/
private static int getWindingRule(FillType type) {
switch (type) {
case WINDING:
case INVERSE_WINDING:
return GeneralPath.WIND_NON_ZERO;
case EVEN_ODD:
case INVERSE_EVEN_ODD:
return GeneralPath.WIND_EVEN_ODD;
}
assert false;
throw new IllegalArgumentException();
}
private static Direction getDirection(int direction) {
for (Direction d : Direction.values()) {
if (direction == d.nativeInt) {
return d;
}
}
assert false;
return null;
}
/**
* Returns whether the path is empty.
* @return true if the path is empty.
*/
private boolean isEmpty() {
return mPath.getCurrentPoint() == null;
}
/**
* Fills the given {@link RectF} with the path bounds.
* @param bounds the RectF to be filled.
*/
private void fillBounds(RectF bounds) {
Rectangle2D rect = mPath.getBounds2D();
bounds.left = (float)rect.getMinX();
bounds.right = (float)rect.getMaxX();
bounds.top = (float)rect.getMinY();
bounds.bottom = (float)rect.getMaxY();
}
/**
* Set the beginning of the next contour to the point (x,y).
*
* @param x The x-coordinate of the start of a new contour
* @param y The y-coordinate of the start of a new contour
*/
private void moveTo(float x, float y) {
mPath.moveTo(mLastX = x, mLastY = y);
}
/**
* Set the beginning of the next contour relative to the last point on the
* previous contour. If there is no previous contour, this is treated the
* same as moveTo().
*
* @param dx The amount to add to the x-coordinate of the end of the
* previous contour, to specify the start of a new contour
* @param dy The amount to add to the y-coordinate of the end of the
* previous contour, to specify the start of a new contour
*/
private void rMoveTo(float dx, float dy) {
dx += mLastX;
dy += mLastY;
mPath.moveTo(mLastX = dx, mLastY = dy);
}
/**
* Add a line from the last point to the specified point (x,y).
* If no moveTo() call has been made for this contour, the first point is
* automatically set to (0,0).
*
* @param x The x-coordinate of the end of a line
* @param y The y-coordinate of the end of a line
*/
private void lineTo(float x, float y) {
mPath.lineTo(mLastX = x, mLastY = y);
}
/**
* Same as lineTo, but the coordinates are considered relative to the last
* point on this contour. If there is no previous point, then a moveTo(0,0)
* is inserted automatically.
*
* @param dx The amount to add to the x-coordinate of the previous point on
* this contour, to specify a line
* @param dy The amount to add to the y-coordinate of the previous point on
* this contour, to specify a line
*/
private void rLineTo(float dx, float dy) {
if (isEmpty()) {
mPath.moveTo(mLastX = 0, mLastY = 0);
}
dx += mLastX;
dy += mLastY;
mPath.lineTo(mLastX = dx, mLastY = dy);
}
/**
* Add a quadratic bezier from the last point, approaching control point
* (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
* this contour, the first point is automatically set to (0,0).
*
* @param x1 The x-coordinate of the control point on a quadratic curve
* @param y1 The y-coordinate of the control point on a quadratic curve
* @param x2 The x-coordinate of the end point on a quadratic curve
* @param y2 The y-coordinate of the end point on a quadratic curve
*/
private void quadTo(float x1, float y1, float x2, float y2) {
mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2);
}
/**
* Same as quadTo, but the coordinates are considered relative to the last
* point on this contour. If there is no previous point, then a moveTo(0,0)
* is inserted automatically.
*
* @param dx1 The amount to add to the x-coordinate of the last point on
* this contour, for the control point of a quadratic curve
* @param dy1 The amount to add to the y-coordinate of the last point on
* this contour, for the control point of a quadratic curve
* @param dx2 The amount to add to the x-coordinate of the last point on
* this contour, for the end point of a quadratic curve
* @param dy2 The amount to add to the y-coordinate of the last point on
* this contour, for the end point of a quadratic curve
*/
private void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
if (isEmpty()) {
mPath.moveTo(mLastX = 0, mLastY = 0);
}
dx1 += mLastX;
dy1 += mLastY;
dx2 += mLastX;
dy2 += mLastY;
mPath.quadTo(dx1, dy1, mLastX = dx2, mLastY = dy2);
}
/**
* Add a cubic bezier from the last point, approaching control points
* (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
* made for this contour, the first point is automatically set to (0,0).
*
* @param x1 The x-coordinate of the 1st control point on a cubic curve
* @param y1 The y-coordinate of the 1st control point on a cubic curve
* @param x2 The x-coordinate of the 2nd control point on a cubic curve
* @param y2 The y-coordinate of the 2nd control point on a cubic curve
* @param x3 The x-coordinate of the end point on a cubic curve
* @param y3 The y-coordinate of the end point on a cubic curve
*/
private void cubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3);
}
/**
* Same as cubicTo, but the coordinates are considered relative to the
* current point on this contour. If there is no previous point, then a
* moveTo(0,0) is inserted automatically.
*/
private void rCubicTo(float dx1, float dy1, float dx2, float dy2,
float dx3, float dy3) {
if (isEmpty()) {
mPath.moveTo(mLastX = 0, mLastY = 0);
}
dx1 += mLastX;
dy1 += mLastY;
dx2 += mLastX;
dy2 += mLastY;
dx3 += mLastX;
dy3 += mLastY;
mPath.curveTo(dx1, dy1, dx2, dy2, mLastX = dx3, mLastY = dy3);
}
/**
* Append the specified arc to the path as a new contour. If the start of
* the path is different from the path's current last point, then an
* automatic lineTo() is added to connect the current contour to the
* start of the arc. However, if the path is empty, then we call moveTo()
* with the first point of the arc. The sweep angle is tread mod 360.
*
* @param oval The bounds of oval defining shape and size of the arc
* @param startAngle Starting angle (in degrees) where the arc begins
* @param sweepAngle Sweep angle (in degrees) measured clockwise, treated
* mod 360.
* @param forceMoveTo If true, always begin a new contour with the arc
*/
private void arcTo(RectF oval, float startAngle, float sweepAngle,
boolean forceMoveTo) {
Arc2D arc = new Arc2D.Float(oval.left, oval.top, oval.width(), oval.height(), startAngle,
sweepAngle, Arc2D.OPEN);
mPath.append(arc, true /*connect*/);
resetLastPointFromPath();
}
/**
* Close the current contour. If the current point is not equal to the
* first point of the contour, a line segment is automatically added.
*/
private void close() {
mPath.closePath();
}
private void resetLastPointFromPath() {
Point2D last = mPath.getCurrentPoint();
mLastX = (float) last.getX();
mLastY = (float) last.getY();
}
/**
* Add a closed rectangle contour to the path
*
* @param left The left side of a rectangle to add to the path
* @param top The top of a rectangle to add to the path
* @param right The right side of a rectangle to add to the path
* @param bottom The bottom of a rectangle to add to the path
* @param dir The direction to wind the rectangle's contour
*/
private void addRect(float left, float top, float right, float bottom,
int dir) {
moveTo(left, top);
Direction direction = getDirection(dir);
switch (direction) {
case CW:
lineTo(right, top);
lineTo(right, bottom);
lineTo(left, bottom);
break;
case CCW:
lineTo(left, bottom);
lineTo(right, bottom);
lineTo(right, top);
break;
}
close();
resetLastPointFromPath();
}
/**
* Offset the path by (dx,dy), returning true on success
*
* @param dx The amount in the X direction to offset the entire path
* @param dy The amount in the Y direction to offset the entire path
* @param dst The translated path is written here. If this is null, then
* the original path is modified.
*/
public void offset(float dx, float dy, Path_Delegate dst) {
GeneralPath newPath = new GeneralPath();
PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
newPath.append(iterator, false /*connect*/);
if (dst != null) {
dst.mPath = newPath;
} else {
mPath = newPath;
}
}
/**
* Transform the points in this path by matrix, and write the answer
* into dst. If dst is null, then the the original path is modified.
*
* @param matrix The matrix to apply to the path
* @param dst The transformed path is written here. If dst is null,
* then the the original path is modified
*/
public void transform(Matrix_Delegate matrix, Path_Delegate dst) {
if (matrix.hasPerspective()) {
assert false;
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
"android.graphics.Path#transform() only " +
"supports affine transformations.", null, null /*data*/);
}
GeneralPath newPath = new GeneralPath();
PathIterator iterator = mPath.getPathIterator(matrix.getAffineTransform());
newPath.append(iterator, false /*connect*/);
if (dst != null) {
dst.mPath = newPath;
} else {
mPath = newPath;
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Composite;
/**
* Delegate implementing the native methods of android.graphics.PixelXorXfermode
*
* Through the layoutlib_create tool, the original native methods of PixelXorXfermode have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original PixelXorXfermode class.
*
* Because this extends {@link Xfermode_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
* {@link Xfermode_Delegate}.
*
* @see Xfermode_Delegate
*/
public class PixelXorXfermode_Delegate extends Xfermode_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public Composite getComposite(int alpha) {
// FIXME
return null;
}
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Pixel XOR Xfermodes are not supported in Layout Preview mode.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate(int opColor) {
PixelXorXfermode_Delegate newDelegate = new PixelXorXfermode_Delegate();
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.PorterDuffColorFilter
*
* Through the layoutlib_create tool, the original native methods of PorterDuffColorFilter have
* been replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original PorterDuffColorFilter class.
*
* Because this extends {@link ColorFilter_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the Shader classes will be added to the manager
* owned by {@link ColorFilter_Delegate}.
*
* @see ColorFilter_Delegate
*
*/
public class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "PorterDuff Color Filters are not supported.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode) {
PorterDuffColorFilter_Delegate newDelegate = new PorterDuffColorFilter_Delegate();
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static int nCreatePorterDuffFilter(int nativeFilter, int srcColor,
int porterDuffMode) {
// pass
return 0;
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.AlphaComposite;
import java.awt.Composite;
/**
* Delegate implementing the native methods of android.graphics.PorterDuffXfermode
*
* Through the layoutlib_create tool, the original native methods of PorterDuffXfermode have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original PorterDuffXfermode class.
*
* Because this extends {@link Xfermode_Delegate}, there's no need to use a
* {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
* {@link Xfermode_Delegate}.
*
*/
public class PorterDuffXfermode_Delegate extends Xfermode_Delegate {
// ---- delegate data ----
private final int mMode;
// ---- Public Helper methods ----
public PorterDuff.Mode getMode() {
return getPorterDuffMode(mMode);
}
@Override
public Composite getComposite(int alpha) {
return getComposite(getPorterDuffMode(mMode), alpha);
}
@Override
public boolean isSupported() {
return true;
}
@Override
public String getSupportMessage() {
// no message since isSupported returns true;
return null;
}
public static PorterDuff.Mode getPorterDuffMode(int mode) {
for (PorterDuff.Mode m : PorterDuff.Mode.values()) {
if (m.nativeInt == mode) {
return m;
}
}
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
String.format("Unknown PorterDuff.Mode: %d", mode), null /*data*/);
assert false;
return PorterDuff.Mode.SRC_OVER;
}
public static Composite getComposite(PorterDuff.Mode mode, int alpha) {
float falpha = alpha != 0xFF ? (float)alpha / 255.f : 1.f;
switch (mode) {
case CLEAR:
return AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha);
case DARKEN:
break;
case DST:
return AlphaComposite.getInstance(AlphaComposite.DST, falpha);
case DST_ATOP:
return AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha);
case DST_IN:
return AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha);
case DST_OUT:
return AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha);
case DST_OVER:
return AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha);
case LIGHTEN:
break;
case MULTIPLY:
break;
case SCREEN:
break;
case SRC:
return AlphaComposite.getInstance(AlphaComposite.SRC, falpha);
case SRC_ATOP:
return AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha);
case SRC_IN:
return AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha);
case SRC_OUT:
return AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha);
case SRC_OVER:
return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha);
case XOR:
return AlphaComposite.getInstance(AlphaComposite.XOR, falpha);
}
Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN,
String.format("Unsupported PorterDuff Mode: %s", mode.name()),
null, null /*data*/);
return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha);
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreateXfermode(int mode) {
PorterDuffXfermode_Delegate newDelegate = new PorterDuffXfermode_Delegate(mode);
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
private PorterDuffXfermode_Delegate(int mode) {
mMode = mode;
}
}

View File

@@ -1,132 +0,0 @@
/*
* Copyright (C) 2008 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 android.graphics;
public class RadialGradient extends GradientShader {
private RadialGradientPaint mPaint;
/**
* Create a shader that draws a radial gradient given the center and radius.
*
* @param x The x-coordinate of the center of the radius
* @param y The y-coordinate of the center of the radius
* @param radius Must be positive. The radius of the circle for this
* gradient
* @param colors The colors to be distributed between the center and edge of
* the circle
* @param positions May be NULL. The relative position of each corresponding
* color in the colors array. If this is NULL, the the colors are
* distributed evenly between the center and edge of the circle.
* @param tile The Shader tiling mode
*/
public RadialGradient(float x, float y, float radius, int colors[], float positions[],
TileMode tile) {
super(colors, positions);
if (radius <= 0) {
throw new IllegalArgumentException("radius must be > 0");
}
mPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
}
/**
* Create a shader that draws a radial gradient given the center and radius.
*
* @param x The x-coordinate of the center of the radius
* @param y The y-coordinate of the center of the radius
* @param radius Must be positive. The radius of the circle for this
* gradient
* @param color0 The color at the center of the circle.
* @param color1 The color at the edge of the circle.
* @param tile The Shader tiling mode
*/
public RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile) {
this(x, y, radius, new int[] { color0, color1 }, null /* positions */, tile);
}
@Override
java.awt.Paint getJavaPaint() {
return mPaint;
}
private static class RadialGradientPaint extends GradientPaint {
private final float mX;
private final float mY;
private final float mRadius;
public RadialGradientPaint(float x, float y, float radius, int[] colors, float[] positions, TileMode mode) {
super(colors, positions, mode);
mX = x;
mY = y;
mRadius = radius;
}
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
java.awt.geom.Rectangle2D userBounds,
java.awt.geom.AffineTransform xform,
java.awt.RenderingHints hints) {
precomputeGradientColors();
return new RadialGradientPaintContext(colorModel);
}
private class RadialGradientPaintContext implements java.awt.PaintContext {
private final java.awt.image.ColorModel mColorModel;
public RadialGradientPaintContext(java.awt.image.ColorModel colorModel) {
mColorModel = colorModel;
}
public void dispose() {
}
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
int[] data = new int[w*h];
// compute distance from each point to the center, and figure out the distance from
// it.
int index = 0;
for (int iy = 0 ; iy < h ; iy++) {
for (int ix = 0 ; ix < w ; ix++) {
float _x = x + ix - mX;
float _y = y + iy - mY;
float distance = (float) Math.sqrt(_x * _x + _y * _y);
data[index++] = getGradientColor(distance / mRadius);
}
}
image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
return image.getRaster();
}
}
}
}

View File

@@ -0,0 +1,211 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Shader.TileMode;
/**
* Delegate implementing the native methods of android.graphics.RadialGradient
*
* Through the layoutlib_create tool, the original native methods of RadialGradient have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original RadialGradient class.
*
* Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
* as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
*
* @see Shader_Delegate
*
*/
public class RadialGradient_Delegate extends Gradient_Delegate {
// ---- delegate data ----
private java.awt.Paint mJavaPaint;
// ---- Public Helper methods ----
@Override
public java.awt.Paint getJavaPaint() {
return mJavaPaint;
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate1(float x, float y, float radius,
int colors[], float positions[], int tileMode) {
RadialGradient_Delegate newDelegate = new RadialGradient_Delegate(x, y, radius,
colors, positions, Shader_Delegate.getTileMode(tileMode));
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static int nativeCreate2(float x, float y, float radius,
int color0, int color1, int tileMode) {
return nativeCreate1(x, y, radius, new int[] { color0, color1 }, null /*positions*/,
tileMode);
}
@LayoutlibDelegate
/*package*/ static int nativePostCreate1(int native_shader, float x, float y, float radius,
int colors[], float positions[], int tileMode) {
// nothing to be done here.
return 0;
}
@LayoutlibDelegate
/*package*/ static int nativePostCreate2(int native_shader, float x, float y, float radius,
int color0, int color1, int tileMode) {
// nothing to be done here.
return 0;
}
// ---- Private delegate/helper methods ----
/**
* Create a shader that draws a radial gradient given the center and radius.
*
* @param x The x-coordinate of the center of the radius
* @param y The y-coordinate of the center of the radius
* @param radius Must be positive. The radius of the circle for this
* gradient
* @param colors The colors to be distributed between the center and edge of
* the circle
* @param positions May be NULL. The relative position of each corresponding
* color in the colors array. If this is NULL, the the colors are
* distributed evenly between the center and edge of the circle.
* @param tile The Shader tiling mode
*/
private RadialGradient_Delegate(float x, float y, float radius, int colors[], float positions[],
TileMode tile) {
super(colors, positions);
mJavaPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
}
private class RadialGradientPaint extends GradientPaint {
private final float mX;
private final float mY;
private final float mRadius;
public RadialGradientPaint(float x, float y, float radius,
int[] colors, float[] positions, TileMode mode) {
super(colors, positions, mode);
mX = x;
mY = y;
mRadius = radius;
}
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
java.awt.geom.Rectangle2D userBounds,
java.awt.geom.AffineTransform xform,
java.awt.RenderingHints hints) {
precomputeGradientColors();
java.awt.geom.AffineTransform canvasMatrix;
try {
canvasMatrix = xform.createInverse();
} catch (java.awt.geom.NoninvertibleTransformException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
"Unable to inverse matrix in RadialGradient", e, null /*data*/);
canvasMatrix = new java.awt.geom.AffineTransform();
}
java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
try {
localMatrix = localMatrix.createInverse();
} catch (java.awt.geom.NoninvertibleTransformException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
"Unable to inverse matrix in RadialGradient", e, null /*data*/);
localMatrix = new java.awt.geom.AffineTransform();
}
return new RadialGradientPaintContext(canvasMatrix, localMatrix, colorModel);
}
private class RadialGradientPaintContext implements java.awt.PaintContext {
private final java.awt.geom.AffineTransform mCanvasMatrix;
private final java.awt.geom.AffineTransform mLocalMatrix;
private final java.awt.image.ColorModel mColorModel;
public RadialGradientPaintContext(
java.awt.geom.AffineTransform canvasMatrix,
java.awt.geom.AffineTransform localMatrix,
java.awt.image.ColorModel colorModel) {
mCanvasMatrix = canvasMatrix;
mLocalMatrix = localMatrix;
mColorModel = colorModel;
}
public void dispose() {
}
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
int[] data = new int[w*h];
// compute distance from each point to the center, and figure out the distance from
// it.
int index = 0;
float[] pt1 = new float[2];
float[] pt2 = new float[2];
for (int iy = 0 ; iy < h ; iy++) {
for (int ix = 0 ; ix < w ; ix++) {
// handle the canvas transform
pt1[0] = x + ix;
pt1[1] = y + iy;
mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
// handle the local matrix
pt1[0] = pt2[0] - mX;
pt1[1] = pt2[1] - mY;
mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
float _x = pt2[0];
float _y = pt2[1];
float distance = (float) Math.sqrt(_x * _x + _y * _y);
data[index++] = getGradientColor(distance / mRadius);
}
}
image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
return image.getRaster();
}
}
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.Rasterizer
*
* Through the layoutlib_create tool, the original native methods of Rasterizer have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original Rasterizer class.
*
* This also serve as a base class for all Rasterizer delegate classes.
*
* @see DelegateManager
*
*/
public abstract class Rasterizer_Delegate {
// ---- delegate manager ----
protected static final DelegateManager<Rasterizer_Delegate> sManager =
new DelegateManager<Rasterizer_Delegate>(Rasterizer_Delegate.class);
// ---- delegate helper data ----
// ---- delegate data ----
// ---- Public Helper methods ----
public static Rasterizer_Delegate getDelegate(int nativeShader) {
return sManager.getDelegate(nativeShader);
}
public abstract boolean isSupported();
public abstract String getSupportMessage();
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static void finalizer(int native_instance) {
sManager.removeJavaReferenceFor(native_instance);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,484 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.os.Parcel;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
/**
* Delegate implementing the native methods of android.graphics.Region
*
* Through the layoutlib_create tool, the original native methods of Region have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original Region class.
*
* This also serve as a base class for all Region delegate classes.
*
* @see DelegateManager
*
*/
public class Region_Delegate {
// ---- delegate manager ----
protected static final DelegateManager<Region_Delegate> sManager =
new DelegateManager<Region_Delegate>(Region_Delegate.class);
// ---- delegate helper data ----
// ---- delegate data ----
private Area mArea = new Area();
// ---- Public Helper methods ----
public static Region_Delegate getDelegate(int nativeShader) {
return sManager.getDelegate(nativeShader);
}
public Area getJavaArea() {
return mArea;
}
/**
* Combines two {@link Shape} into another one (actually an {@link Area}), according
* to the given {@link Region.Op}.
*
* If the Op is not one that combines two shapes, then this return null
*
* @param shape1 the firt shape to combine which can be null if there's no original clip.
* @param shape2 the 2nd shape to combine
* @param regionOp the operande for the combine
* @return a new area or null.
*/
public static Area combineShapes(Shape shape1, Shape shape2, int regionOp) {
if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
// if shape1 is null (empty), then the result is null.
if (shape1 == null) {
return null;
}
// result is always a new area.
Area result = new Area(shape1);
result.subtract(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
return result;
} else if (regionOp == Region.Op.INTERSECT.nativeInt) {
// if shape1 is null, then the result is simply shape2.
if (shape1 == null) {
return new Area(shape2);
}
// result is always a new area.
Area result = new Area(shape1);
result.intersect(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
return result;
} else if (regionOp == Region.Op.UNION.nativeInt) {
// if shape1 is null, then the result is simply shape2.
if (shape1 == null) {
return new Area(shape2);
}
// result is always a new area.
Area result = new Area(shape1);
result.add(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
return result;
} else if (regionOp == Region.Op.XOR.nativeInt) {
// if shape1 is null, then the result is simply shape2
if (shape1 == null) {
return new Area(shape2);
}
// result is always a new area.
Area result = new Area(shape1);
result.exclusiveOr(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
return result;
} else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) {
// result is always a new area.
Area result = new Area(shape2);
if (shape1 != null) {
result.subtract(shape1 instanceof Area ? (Area) shape1 : new Area(shape1));
}
return result;
}
return null;
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static boolean isEmpty(Region thisRegion) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
return true;
}
return regionDelegate.mArea.isEmpty();
}
@LayoutlibDelegate
/*package*/ static boolean isRect(Region thisRegion) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
return true;
}
return regionDelegate.mArea.isRectangular();
}
@LayoutlibDelegate
/*package*/ static boolean isComplex(Region thisRegion) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
return true;
}
return regionDelegate.mArea.isSingular() == false;
}
@LayoutlibDelegate
/*package*/ static boolean contains(Region thisRegion, int x, int y) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
return false;
}
return regionDelegate.mArea.contains(x, y);
}
@LayoutlibDelegate
/*package*/ static boolean quickContains(Region thisRegion,
int left, int top, int right, int bottom) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
return false;
}
return regionDelegate.mArea.isRectangular() &&
regionDelegate.mArea.contains(left, top, right - left, bottom - top);
}
@LayoutlibDelegate
/*package*/ static boolean quickReject(Region thisRegion,
int left, int top, int right, int bottom) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
return false;
}
return regionDelegate.mArea.isEmpty() ||
regionDelegate.mArea.intersects(left, top, right - left, bottom - top) == false;
}
@LayoutlibDelegate
/*package*/ static boolean quickReject(Region thisRegion, Region rgn) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
return false;
}
Region_Delegate targetRegionDelegate = sManager.getDelegate(rgn.mNativeRegion);
if (targetRegionDelegate == null) {
return false;
}
return regionDelegate.mArea.isEmpty() ||
regionDelegate.mArea.getBounds().intersects(
targetRegionDelegate.mArea.getBounds()) == false;
}
@LayoutlibDelegate
/*package*/ static void translate(Region thisRegion, int dx, int dy, Region dst) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
return;
}
Region_Delegate targetRegionDelegate = sManager.getDelegate(dst.mNativeRegion);
if (targetRegionDelegate == null) {
return;
}
if (regionDelegate.mArea.isEmpty()) {
targetRegionDelegate.mArea = new Area();
} else {
targetRegionDelegate.mArea = new Area(regionDelegate.mArea);
AffineTransform mtx = new AffineTransform();
mtx.translate(dx, dy);
targetRegionDelegate.mArea.transform(mtx);
}
}
@LayoutlibDelegate
/*package*/ static void scale(Region thisRegion, float scale, Region dst) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
return;
}
Region_Delegate targetRegionDelegate = sManager.getDelegate(dst.mNativeRegion);
if (targetRegionDelegate == null) {
return;
}
if (regionDelegate.mArea.isEmpty()) {
targetRegionDelegate.mArea = new Area();
} else {
targetRegionDelegate.mArea = new Area(regionDelegate.mArea);
AffineTransform mtx = new AffineTransform();
mtx.scale(scale, scale);
targetRegionDelegate.mArea.transform(mtx);
}
}
@LayoutlibDelegate
/*package*/ static int nativeConstructor() {
Region_Delegate newDelegate = new Region_Delegate();
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static void nativeDestructor(int native_region) {
sManager.removeJavaReferenceFor(native_region);
}
@LayoutlibDelegate
/*package*/ static boolean nativeSetRegion(int native_dst, int native_src) {
Region_Delegate dstRegion = sManager.getDelegate(native_dst);
if (dstRegion == null) {
return true;
}
Region_Delegate srcRegion = sManager.getDelegate(native_src);
if (srcRegion == null) {
return true;
}
dstRegion.mArea.reset();
dstRegion.mArea.add(srcRegion.mArea);
return true;
}
@LayoutlibDelegate
/*package*/ static boolean nativeSetRect(int native_dst,
int left, int top, int right, int bottom) {
Region_Delegate dstRegion = sManager.getDelegate(native_dst);
if (dstRegion == null) {
return true;
}
dstRegion.mArea = new Area(new Rectangle2D.Float(left, top, right - left, bottom - top));
return dstRegion.mArea.getBounds().isEmpty() == false;
}
@LayoutlibDelegate
/*package*/ static boolean nativeSetPath(int native_dst, int native_path, int native_clip) {
Region_Delegate dstRegion = sManager.getDelegate(native_dst);
if (dstRegion == null) {
return true;
}
Path_Delegate path = Path_Delegate.getDelegate(native_path);
if (path == null) {
return true;
}
dstRegion.mArea = new Area(path.getJavaShape());
Region_Delegate clip = sManager.getDelegate(native_clip);
if (clip != null) {
dstRegion.mArea.subtract(clip.getJavaArea());
}
return dstRegion.mArea.getBounds().isEmpty() == false;
}
@LayoutlibDelegate
/*package*/ static boolean nativeGetBounds(int native_region, Rect rect) {
Region_Delegate region = sManager.getDelegate(native_region);
if (region == null) {
return true;
}
Rectangle bounds = region.mArea.getBounds();
if (bounds.isEmpty()) {
rect.left = rect.top = rect.right = rect.bottom = 0;
return false;
}
rect.left = bounds.x;
rect.top = bounds.y;
rect.right = bounds.x + bounds.width;
rect.bottom = bounds.y + bounds.height;
return true;
}
@LayoutlibDelegate
/*package*/ static boolean nativeGetBoundaryPath(int native_region, int native_path) {
Region_Delegate region = sManager.getDelegate(native_region);
if (region == null) {
return false;
}
Path_Delegate path = Path_Delegate.getDelegate(native_path);
if (path == null) {
return false;
}
if (region.mArea.isEmpty()) {
path.reset();
return false;
}
path.setPathIterator(region.mArea.getPathIterator(new AffineTransform()));
return true;
}
@LayoutlibDelegate
/*package*/ static boolean nativeOp(int native_dst,
int left, int top, int right, int bottom, int op) {
Region_Delegate region = sManager.getDelegate(native_dst);
if (region == null) {
return false;
}
region.mArea = combineShapes(region.mArea,
new Rectangle2D.Float(left, top, right - left, bottom - top), op);
assert region.mArea != null;
if (region.mArea != null) {
region.mArea = new Area();
}
return region.mArea.getBounds().isEmpty() == false;
}
@LayoutlibDelegate
/*package*/ static boolean nativeOp(int native_dst, Rect rect, int native_region, int op) {
Region_Delegate region = sManager.getDelegate(native_dst);
if (region == null) {
return false;
}
region.mArea = combineShapes(region.mArea,
new Rectangle2D.Float(rect.left, rect.top, rect.width(), rect.height()), op);
assert region.mArea != null;
if (region.mArea != null) {
region.mArea = new Area();
}
return region.mArea.getBounds().isEmpty() == false;
}
@LayoutlibDelegate
/*package*/ static boolean nativeOp(int native_dst,
int native_region1, int native_region2, int op) {
Region_Delegate dstRegion = sManager.getDelegate(native_dst);
if (dstRegion == null) {
return true;
}
Region_Delegate region1 = sManager.getDelegate(native_region1);
if (region1 == null) {
return false;
}
Region_Delegate region2 = sManager.getDelegate(native_region2);
if (region2 == null) {
return false;
}
dstRegion.mArea = combineShapes(region1.mArea, region2.mArea, op);
assert dstRegion.mArea != null;
if (dstRegion.mArea != null) {
dstRegion.mArea = new Area();
}
return dstRegion.mArea.getBounds().isEmpty() == false;
}
@LayoutlibDelegate
/*package*/ static int nativeCreateFromParcel(Parcel p) {
// This is only called by Region.CREATOR (Parcelable.Creator<Region>), which is only
// used during aidl call so really this should not be called.
Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
"AIDL is not suppored, and therefore Regions cannot be created from parcels.",
null /*data*/);
return 0;
}
@LayoutlibDelegate
/*package*/ static boolean nativeWriteToParcel(int native_region,
Parcel p) {
// This is only called when sending a region through aidl, so really this should not
// be called.
Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
"AIDL is not suppored, and therefore Regions cannot be written to parcels.",
null /*data*/);
return false;
}
@LayoutlibDelegate
/*package*/ static boolean nativeEquals(int native_r1, int native_r2) {
Region_Delegate region1 = sManager.getDelegate(native_r1);
if (region1 == null) {
return false;
}
Region_Delegate region2 = sManager.getDelegate(native_r2);
if (region2 == null) {
return false;
}
return region1.mArea.equals(region2.mArea);
}
@LayoutlibDelegate
/*package*/ static String nativeToString(int native_region) {
Region_Delegate region = sManager.getDelegate(native_region);
if (region == null) {
return "not found";
}
return region.mArea.toString();
}
// ---- Private delegate/helper methods ----
}

View File

@@ -1,83 +0,0 @@
/*
* Copyright (C) 2008 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 android.graphics;
/**
* Shader is the based class for objects that return horizontal spans of colors
* during drawing. A subclass of Shader is installed in a Paint calling
* paint.setShader(shader). After that any object (other than a bitmap) that is
* drawn with that paint will get its color(s) from the shader.
*/
public abstract class Shader {
private final Matrix mMatrix = new Matrix();
public enum TileMode {
/**
* replicate the edge color if the shader draws outside of its
* original bounds
*/
CLAMP (0),
/**
* repeat the shader's image horizontally and vertically
*/
REPEAT (1),
/**
* repeat the shader's image horizontally and vertically, alternating
* mirror images so that adjacent images always seam
*/
MIRROR (2);
TileMode(int nativeInt) {
this.nativeInt = nativeInt;
}
final int nativeInt;
}
/**
* Return true if the shader has a non-identity local matrix.
* @param localM If not null, it is set to the shader's local matrix.
* @return true if the shader has a non-identity local matrix
*/
public boolean getLocalMatrix(Matrix localM) {
if (localM != null) {
localM.set(mMatrix);
}
return !mMatrix.isIdentity();
}
/**
* Set the shader's local matrix. Passing null will reset the shader's
* matrix to identity
* @param localM The shader's new local matrix, or null to specify identity
*/
public void setLocalMatrix(Matrix localM) {
if (localM != null) {
mMatrix.set(localM);
} else {
mMatrix.reset();
}
}
/**
* Returns a java.awt.Paint object matching this shader.
*/
abstract java.awt.Paint getJavaPaint();
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Shader.TileMode;
/**
* Delegate implementing the native methods of android.graphics.Shader
*
* Through the layoutlib_create tool, the original native methods of Shader have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original Shader class.
*
* This also serve as a base class for all Shader delegate classes.
*
* @see DelegateManager
*
*/
public abstract class Shader_Delegate {
// ---- delegate manager ----
protected static final DelegateManager<Shader_Delegate> sManager =
new DelegateManager<Shader_Delegate>(Shader_Delegate.class);
// ---- delegate helper data ----
// ---- delegate data ----
private Matrix_Delegate mLocalMatrix = null;
// ---- Public Helper methods ----
public static Shader_Delegate getDelegate(int nativeShader) {
return sManager.getDelegate(nativeShader);
}
/**
* Returns the {@link TileMode} matching the given int.
* @param tileMode the tile mode int value
* @return the TileMode enum.
*/
public static TileMode getTileMode(int tileMode) {
for (TileMode tm : TileMode.values()) {
if (tm.nativeInt == tileMode) {
return tm;
}
}
assert false;
return TileMode.CLAMP;
}
public abstract java.awt.Paint getJavaPaint();
public abstract boolean isSupported();
public abstract String getSupportMessage();
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static void nativeDestructor(int native_shader, int native_skiaShader) {
sManager.removeJavaReferenceFor(native_shader);
}
@LayoutlibDelegate
/*package*/ static void nativeSetLocalMatrix(int native_shader, int native_skiaShader,
int matrix_instance) {
// get the delegate from the native int.
Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
if (shaderDelegate == null) {
return;
}
shaderDelegate.mLocalMatrix = Matrix_Delegate.getDelegate(matrix_instance);
}
// ---- Private delegate/helper methods ----
protected java.awt.geom.AffineTransform getLocalMatrix() {
if (mLocalMatrix != null) {
return mLocalMatrix.getAffineTransform();
}
return new java.awt.geom.AffineTransform();
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
/**
* Delegate implementing the native methods of android.graphics.SumPathEffect
*
* Through the layoutlib_create tool, the original native methods of SumPathEffect have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original SumPathEffect class.
*
* Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
* as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
*
* @see PathEffect_Delegate
*
*/
public class SumPathEffect_Delegate extends PathEffect_Delegate {
// ---- delegate data ----
// ---- Public Helper methods ----
@Override
public Stroke getStroke(Paint_Delegate paint) {
// FIXME
return null;
}
@Override
public boolean isSupported() {
return false;
}
@Override
public String getSupportMessage() {
return "Sum Path Effects are not supported in Layout Preview mode.";
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate(int first, int second) {
SumPathEffect_Delegate newDelegate = new SumPathEffect_Delegate();
return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -1,140 +0,0 @@
/*
* Copyright (C) 2008 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 android.graphics;
public class SweepGradient extends GradientShader {
private SweepGradientPaint mPaint;
/**
* A subclass of Shader that draws a sweep gradient around a center point.
*
* @param cx The x-coordinate of the center
* @param cy The y-coordinate of the center
* @param colors The colors to be distributed between around the center.
* There must be at least 2 colors in the array.
* @param positions May be NULL. The relative position of
* each corresponding color in the colors array, beginning
* with 0 and ending with 1.0. If the values are not
* monotonic, the drawing may produce unexpected results.
* If positions is NULL, then the colors are automatically
* spaced evenly.
*/
public SweepGradient(float cx, float cy,
int colors[], float positions[]) {
super(colors, positions);
mPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
}
/**
* A subclass of Shader that draws a sweep gradient around a center point.
*
* @param cx The x-coordinate of the center
* @param cy The y-coordinate of the center
* @param color0 The color to use at the start of the sweep
* @param color1 The color to use at the end of the sweep
*/
public SweepGradient(float cx, float cy, int color0, int color1) {
this(cx, cy, new int[] { color0, color1}, null /*positions*/);
}
@Override
java.awt.Paint getJavaPaint() {
return mPaint;
}
private static class SweepGradientPaint extends GradientPaint {
private final float mCx;
private final float mCy;
public SweepGradientPaint(float cx, float cy, int[] colors, float[] positions) {
super(colors, positions, null /*tileMode*/);
mCx = cx;
mCy = cy;
}
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
java.awt.geom.Rectangle2D userBounds,
java.awt.geom.AffineTransform xform,
java.awt.RenderingHints hints) {
precomputeGradientColors();
return new SweepGradientPaintContext(colorModel);
}
private class SweepGradientPaintContext implements java.awt.PaintContext {
private final java.awt.image.ColorModel mColorModel;
public SweepGradientPaintContext(java.awt.image.ColorModel colorModel) {
mColorModel = colorModel;
}
public void dispose() {
}
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
int[] data = new int[w*h];
// compute angle from each point to the center, and figure out the distance from
// it.
int index = 0;
for (int iy = 0 ; iy < h ; iy++) {
for (int ix = 0 ; ix < w ; ix++) {
float dx = x + ix - mCx;
float dy = y + iy - mCy;
float angle;
if (dx == 0) {
angle = (float) (dy < 0 ? 3 * Math.PI / 2 : Math.PI / 2);
} else if (dy == 0) {
angle = (float) (dx < 0 ? Math.PI : 0);
} else {
angle = (float) Math.atan(dy / dx);
if (dx > 0) {
if (dy < 0) {
angle += Math.PI * 2;
}
} else {
angle += Math.PI;
}
}
// convert to 0-1. value and get color
data[index++] = getGradientColor((float) (angle / (2 * Math.PI)));
}
}
image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
return image.getRaster();
}
}
}
}

View File

@@ -0,0 +1,218 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.SweepGradient
*
* Through the layoutlib_create tool, the original native methods of SweepGradient have been
* replaced by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original SweepGradient class.
*
* Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
* as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
*
* @see Shader_Delegate
*
*/
public class SweepGradient_Delegate extends Gradient_Delegate {
// ---- delegate data ----
private java.awt.Paint mJavaPaint;
// ---- Public Helper methods ----
@Override
public java.awt.Paint getJavaPaint() {
return mJavaPaint;
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static int nativeCreate1(float x, float y, int colors[], float positions[]) {
SweepGradient_Delegate newDelegate = new SweepGradient_Delegate(x, y, colors, positions);
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static int nativeCreate2(float x, float y, int color0, int color1) {
return nativeCreate1(x, y, new int[] { color0, color1 }, null /*positions*/);
}
@LayoutlibDelegate
/*package*/ static int nativePostCreate1(int native_shader, float cx, float cy,
int[] colors, float[] positions) {
// nothing to be done here.
return 0;
}
@LayoutlibDelegate
/*package*/ static int nativePostCreate2(int native_shader, float cx, float cy,
int color0, int color1) {
// nothing to be done here.
return 0;
}
// ---- Private delegate/helper methods ----
/**
* A subclass of Shader that draws a sweep gradient around a center point.
*
* @param cx The x-coordinate of the center
* @param cy The y-coordinate of the center
* @param colors The colors to be distributed between around the center.
* There must be at least 2 colors in the array.
* @param positions May be NULL. The relative position of
* each corresponding color in the colors array, beginning
* with 0 and ending with 1.0. If the values are not
* monotonic, the drawing may produce unexpected results.
* If positions is NULL, then the colors are automatically
* spaced evenly.
*/
private SweepGradient_Delegate(float cx, float cy,
int colors[], float positions[]) {
super(colors, positions);
mJavaPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
}
private class SweepGradientPaint extends GradientPaint {
private final float mCx;
private final float mCy;
public SweepGradientPaint(float cx, float cy, int[] colors,
float[] positions) {
super(colors, positions, null /*tileMode*/);
mCx = cx;
mCy = cy;
}
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
java.awt.geom.Rectangle2D userBounds,
java.awt.geom.AffineTransform xform,
java.awt.RenderingHints hints) {
precomputeGradientColors();
java.awt.geom.AffineTransform canvasMatrix;
try {
canvasMatrix = xform.createInverse();
} catch (java.awt.geom.NoninvertibleTransformException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
"Unable to inverse matrix in SweepGradient", e, null /*data*/);
canvasMatrix = new java.awt.geom.AffineTransform();
}
java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
try {
localMatrix = localMatrix.createInverse();
} catch (java.awt.geom.NoninvertibleTransformException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
"Unable to inverse matrix in SweepGradient", e, null /*data*/);
localMatrix = new java.awt.geom.AffineTransform();
}
return new SweepGradientPaintContext(canvasMatrix, localMatrix, colorModel);
}
private class SweepGradientPaintContext implements java.awt.PaintContext {
private final java.awt.geom.AffineTransform mCanvasMatrix;
private final java.awt.geom.AffineTransform mLocalMatrix;
private final java.awt.image.ColorModel mColorModel;
public SweepGradientPaintContext(
java.awt.geom.AffineTransform canvasMatrix,
java.awt.geom.AffineTransform localMatrix,
java.awt.image.ColorModel colorModel) {
mCanvasMatrix = canvasMatrix;
mLocalMatrix = localMatrix;
mColorModel = colorModel;
}
public void dispose() {
}
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
int[] data = new int[w*h];
// compute angle from each point to the center, and figure out the distance from
// it.
int index = 0;
float[] pt1 = new float[2];
float[] pt2 = new float[2];
for (int iy = 0 ; iy < h ; iy++) {
for (int ix = 0 ; ix < w ; ix++) {
// handle the canvas transform
pt1[0] = x + ix;
pt1[1] = y + iy;
mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
// handle the local matrix
pt1[0] = pt2[0] - mCx;
pt1[1] = pt2[1] - mCy;
mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
float dx = pt2[0];
float dy = pt2[1];
float angle;
if (dx == 0) {
angle = (float) (dy < 0 ? 3 * Math.PI / 2 : Math.PI / 2);
} else if (dy == 0) {
angle = (float) (dx < 0 ? Math.PI : 0);
} else {
angle = (float) Math.atan(dy / dx);
if (dx > 0) {
if (dy < 0) {
angle += Math.PI * 2;
}
} else {
angle += Math.PI;
}
}
// convert to 0-1. value and get color
data[index++] = getGradientColor((float) (angle / (2 * Math.PI)));
}
}
image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
return image.getRaster();
}
}
}
}

View File

@@ -1,190 +0,0 @@
/*
* Copyright (C) 2008 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 android.graphics;
import com.android.layoutlib.bridge.FontLoader;
import android.content.res.AssetManager;
import java.awt.Font;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Re-implementation of Typeface over java.awt
*/
public class Typeface {
private static final String DEFAULT_FAMILY = "sans-serif";
private static final int[] styleBuffer = new int[1];
/** The default NORMAL typeface object */
public static Typeface DEFAULT;
/**
* The default BOLD typeface object. Note: this may be not actually be
* bold, depending on what fonts are installed. Call getStyle() to know
* for sure.
*/
public static Typeface DEFAULT_BOLD;
/** The NORMAL style of the default sans serif typeface. */
public static Typeface SANS_SERIF;
/** The NORMAL style of the default serif typeface. */
public static Typeface SERIF;
/** The NORMAL style of the default monospace typeface. */
public static Typeface MONOSPACE;
private static Typeface[] sDefaults;
private static FontLoader mFontLoader;
private final int mStyle;
private final List<Font> mFonts;
private final String mFamily;
// Style
public static final int NORMAL = _Original_Typeface.NORMAL;
public static final int BOLD = _Original_Typeface.BOLD;
public static final int ITALIC = _Original_Typeface.ITALIC;
public static final int BOLD_ITALIC = _Original_Typeface.BOLD_ITALIC;
/**
* Returns the underlying {@link Font} objects. The first item in the list is the real
* font. Any other items are fallback fonts for characters not found in the first one.
*/
public List<Font> getFonts() {
return mFonts;
}
/** Returns the typeface's intrinsic style attributes */
public int getStyle() {
return mStyle;
}
/** Returns true if getStyle() has the BOLD bit set. */
public final boolean isBold() {
return (getStyle() & BOLD) != 0;
}
/** Returns true if getStyle() has the ITALIC bit set. */
public final boolean isItalic() {
return (getStyle() & ITALIC) != 0;
}
/**
* Create a typeface object given a family name, and option style information.
* If null is passed for the name, then the "default" font will be chosen.
* The resulting typeface object can be queried (getStyle()) to discover what
* its "real" style characteristics are.
*
* @param familyName May be null. The name of the font family.
* @param style The style (normal, bold, italic) of the typeface.
* e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
* @return The best matching typeface.
*/
public static Typeface create(String familyName, int style) {
styleBuffer[0] = style;
Font font = mFontLoader.getFont(familyName, styleBuffer);
if (font != null) {
ArrayList<Font> list = new ArrayList<Font>();
list.add(font);
list.addAll(mFontLoader.getFallBackFonts());
return new Typeface(familyName, styleBuffer[0], list);
}
return null;
}
/**
* Create a typeface object that best matches the specified existing
* typeface and the specified Style. Use this call if you want to pick a new
* style from the same family of an existing typeface object. If family is
* null, this selects from the default font's family.
*
* @param family May be null. The name of the existing type face.
* @param style The style (normal, bold, italic) of the typeface.
* e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
* @return The best matching typeface.
*/
public static Typeface create(Typeface family, int style) {
styleBuffer[0] = style;
Font font = mFontLoader.getFont(family.mFamily, styleBuffer);
if (font != null) {
ArrayList<Font> list = new ArrayList<Font>();
list.add(font);
list.addAll(mFontLoader.getFallBackFonts());
return new Typeface(family.mFamily, styleBuffer[0], list);
}
return null;
}
/**
* Returns one of the default typeface objects, based on the specified style
*
* @return the default typeface that corresponds to the style
*/
public static Typeface defaultFromStyle(int style) {
return sDefaults[style];
}
/**
* Create a new typeface from the specified font data.
* @param mgr The application's asset manager
* @param path The file name of the font data in the assets directory
* @return The new typeface.
*/
public static Typeface createFromAsset(AssetManager mgr, String path) {
return null;
//return new Typeface(nativeCreateFromAsset(mgr, path));
}
// don't allow clients to call this directly
private Typeface(String family, int style, List<Font> fonts) {
mFamily = family;
mFonts = Collections.unmodifiableList(fonts);
mStyle = style;
}
public static void init(FontLoader fontLoader) {
mFontLoader = fontLoader;
DEFAULT = create(DEFAULT_FAMILY, NORMAL);
DEFAULT_BOLD = create(DEFAULT_FAMILY, BOLD);
SANS_SERIF = create("sans-serif", NORMAL);
SERIF = create("serif", NORMAL);
MONOSPACE = create("monospace", NORMAL);
sDefaults = new Typeface[] {
DEFAULT,
DEFAULT_BOLD,
create(DEFAULT_FAMILY, ITALIC),
create(DEFAULT_FAMILY, BOLD_ITALIC),
};
/*
DEFAULT = create((String)null, 0);
DEFAULT_BOLD = create((String)null, Typeface.BOLD);
SANS_SERIF = create("sans-serif", 0);
SERIF = create("serif", 0);
MONOSPACE = create("monospace", 0);
sDefaults = new Typeface[] {
DEFAULT,
DEFAULT_BOLD,
create((String)null, Typeface.ITALIC),
create((String)null, Typeface.BOLD_ITALIC),
};*/
}
}

View File

@@ -0,0 +1,191 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.impl.FontLoader;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.content.res.AssetManager;
import java.awt.Font;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Delegate implementing the native methods of android.graphics.Typeface
*
* Through the layoutlib_create tool, the original native methods of Typeface have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original Typeface class.
*
* @see DelegateManager
*
*/
public final class Typeface_Delegate {
// ---- delegate manager ----
private static final DelegateManager<Typeface_Delegate> sManager =
new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class);
// ---- delegate helper data ----
private static final String DEFAULT_FAMILY = "sans-serif";
private static final int[] STYLE_BUFFER = new int[1];
private static FontLoader sFontLoader;
private static final List<Typeface_Delegate> sPostInitDelegate =
new ArrayList<Typeface_Delegate>();
// ---- delegate data ----
private final String mFamily;
private int mStyle;
private List<Font> mFonts;
// ---- Public Helper methods ----
public static synchronized void init(FontLoader fontLoader) {
sFontLoader = fontLoader;
for (Typeface_Delegate delegate : sPostInitDelegate) {
delegate.init();
}
sPostInitDelegate.clear();
}
public static Typeface_Delegate getDelegate(int nativeTypeface) {
return sManager.getDelegate(nativeTypeface);
}
public static List<Font> getFonts(Typeface typeface) {
return getFonts(typeface.native_instance);
}
public static List<Font> getFonts(int native_int) {
Typeface_Delegate delegate = sManager.getDelegate(native_int);
if (delegate == null) {
return null;
}
return delegate.getFonts();
}
public List<Font> getFonts() {
return mFonts;
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static synchronized int nativeCreate(String familyName, int style) {
if (familyName == null) {
familyName = DEFAULT_FAMILY;
}
Typeface_Delegate newDelegate = new Typeface_Delegate(familyName, style);
if (sFontLoader != null) {
newDelegate.init();
} else {
// font loader has not been initialized yet, add the delegate to a list of delegates
// to init when the font loader is initialized.
// There won't be any rendering before this happens anyway.
sPostInitDelegate.add(newDelegate);
}
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static synchronized int nativeCreateFromTypeface(int native_instance, int style) {
Typeface_Delegate delegate = sManager.getDelegate(native_instance);
if (delegate == null) {
return 0;
}
Typeface_Delegate newDelegate = new Typeface_Delegate(delegate.mFamily, style);
if (sFontLoader != null) {
newDelegate.init();
} else {
// font loader has not been initialized yet, add the delegate to a list of delegates
// to init when the font loader is initialized.
// There won't be any rendering before this happens anyway.
sPostInitDelegate.add(newDelegate);
}
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
/*package*/ static synchronized int nativeCreateFromAsset(AssetManager mgr, String path) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Typeface.createFromAsset() is not supported.", null /*throwable*/, null /*data*/);
return 0;
}
@LayoutlibDelegate
/*package*/ static synchronized int nativeCreateFromFile(String path) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Typeface.createFromFile() is not supported.", null /*throwable*/, null /*data*/);
return 0;
}
@LayoutlibDelegate
/*package*/ static void nativeUnref(int native_instance) {
sManager.removeJavaReferenceFor(native_instance);
}
@LayoutlibDelegate
/*package*/ static int nativeGetStyle(int native_instance) {
Typeface_Delegate delegate = sManager.getDelegate(native_instance);
if (delegate == null) {
return 0;
}
return delegate.mStyle;
}
@LayoutlibDelegate
/*package*/ static void setGammaForText(float blackGamma, float whiteGamma) {
// This is for device testing only: pass
}
// ---- Private delegate/helper methods ----
private Typeface_Delegate(String family, int style) {
mFamily = family;
mStyle = style;
}
private void init() {
STYLE_BUFFER[0] = mStyle;
Font font = sFontLoader.getFont(mFamily, STYLE_BUFFER);
if (font != null) {
List<Font> list = new ArrayList<Font>();
list.add(font);
list.addAll(sFontLoader.getFallBackFonts());
mFonts = Collections.unmodifiableList(list);
mStyle = STYLE_BUFFER[0];
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2010 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 android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Composite;
/**
* Delegate implementing the native methods of android.graphics.Xfermode
*
* Through the layoutlib_create tool, the original native methods of Xfermode have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original Xfermode class.
*
* This also serve as a base class for all Xfermode delegate classes.
*
* @see DelegateManager
*
*/
public abstract class Xfermode_Delegate {
// ---- delegate manager ----
protected static final DelegateManager<Xfermode_Delegate> sManager =
new DelegateManager<Xfermode_Delegate>(Xfermode_Delegate.class);
// ---- delegate helper data ----
// ---- delegate data ----
// ---- Public Helper methods ----
public static Xfermode_Delegate getDelegate(int native_instance) {
return sManager.getDelegate(native_instance);
}
public abstract Composite getComposite(int alpha);
public abstract boolean isSupported();
public abstract String getSupportMessage();
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static void finalizer(int native_instance) {
sManager.removeJavaReferenceFor(native_instance);
}
// ---- Private delegate/helper methods ----
}

View File

@@ -0,0 +1,48 @@
/*
* 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 android.os;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.util.Map;
/**
* Delegate implementing the native methods of android.os.Build
*
* Through the layoutlib_create tool, the original native methods of Build have been replaced
* by calls to methods of the same name in this delegate class.
*
* Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
* around to map int to instance of the delegate.
*
*/
public class Build_Delegate {
@LayoutlibDelegate
/*package*/ static String getString(String property) {
Map<String, String> properties = Bridge.getPlatformProperties();
String value = properties.get(property);
if (value != null) {
return value;
}
return Build.UNKNOWN;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2010 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 android.os;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate overriding selected methods of android.os.Handler
*
* Through the layoutlib_create tool, selected methods of Handler have been replaced
* by calls to methods of the same name in this delegate class.
*
*
*/
public class Handler_Delegate {
// -------- Delegate methods
@LayoutlibDelegate
/*package*/ static boolean sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
// get the callback
IHandlerCallback callback = sCallbacks.get();
if (callback != null) {
callback.sendMessageAtTime(handler, msg, uptimeMillis);
}
return true;
}
// -------- Delegate implementation
public interface IHandlerCallback {
void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis);
}
private final static ThreadLocal<IHandlerCallback> sCallbacks =
new ThreadLocal<IHandlerCallback>();
public static void setCallback(IHandlerCallback callback) {
sCallbacks.set(callback);
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2010 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 android.os;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.os.SystemClock
*
* Through the layoutlib_create tool, the original native methods of SystemClock have been replaced
* by calls to methods of the same name in this delegate class.
*
* Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
* around to map int to instance of the delegate.
*
*/
public class SystemClock_Delegate {
private static long sBootTime = System.currentTimeMillis();
@LayoutlibDelegate
/*package*/ static boolean setCurrentTimeMillis(long millis) {
return true;
}
/**
* Returns milliseconds since boot, not counting time spent in deep sleep.
* <b>Note:</b> This value may get reset occasionally (before it would
* otherwise wrap around).
*
* @return milliseconds of non-sleep uptime since boot.
*/
@LayoutlibDelegate
/*package*/ static long uptimeMillis() {
return System.currentTimeMillis() - sBootTime;
}
/**
* Returns milliseconds since boot, including time spent in sleep.
*
* @return elapsed milliseconds since boot.
*/
@LayoutlibDelegate
/*package*/ static long elapsedRealtime() {
return System.currentTimeMillis() - sBootTime;
}
/**
* Returns milliseconds running in the current thread.
*
* @return elapsed milliseconds in the thread
*/
@LayoutlibDelegate
/*package*/ static long currentThreadTimeMillis() {
return System.currentTimeMillis();
}
}

View File

@@ -16,20 +16,23 @@
package android.util;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Reimplements _Original_FloatMath with the standard libraries.
*
* Math routines similar to those found in {@link java.lang.Math}. Performs
* computations on {@code float} values directly without incurring the overhead
* of conversions to and from {@code double}.
* Delegate implementing the native methods of android.util.FloatMath
*
* Through the layoutlib_create tool, the original native methods of FloatMath have been replaced
* by calls to methods of the same name in this delegate class.
*
* Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
* around to map int to instance of the delegate.
*
* <p>On one platform, {@code FloatMath.sqrt(100)} executes in one third of the
* time required by {@code java.lang.Math.sqrt(100)}.</p>
*/
public class FloatMath {
/*package*/ final class FloatMath_Delegate {
/** Prevents instantiation. */
private FloatMath() {}
private FloatMath_Delegate() {}
/**
* Returns the float conversion of the most positive (i.e. closest to
@@ -38,7 +41,8 @@ public class FloatMath {
* @param value to be converted
* @return the floor of value
*/
public static float floor(float value) {
@LayoutlibDelegate
/*package*/ static float floor(float value) {
return (float)Math.floor(value);
}
@@ -49,7 +53,8 @@ public class FloatMath {
* @param value to be converted
* @return the ceiling of value
*/
public static float ceil(float value) {
@LayoutlibDelegate
/*package*/ static float ceil(float value) {
return (float)Math.ceil(value);
}
@@ -59,7 +64,8 @@ public class FloatMath {
* @param angle to compute the cosine of, in radians
* @return the sine of angle
*/
public static float sin(float angle) {
@LayoutlibDelegate
/*package*/ static float sin(float angle) {
return (float)Math.sin(angle);
}
@@ -69,7 +75,8 @@ public class FloatMath {
* @param angle to compute the cosine of, in radians
* @return the cosine of angle
*/
public static float cos(float angle) {
@LayoutlibDelegate
/*package*/ static float cos(float angle) {
return (float)Math.cos(angle);
}
@@ -80,7 +87,8 @@ public class FloatMath {
* @param value to compute sqrt of
* @return the square root of value
*/
public static float sqrt(float value) {
@LayoutlibDelegate
/*package*/ static float sqrt(float value) {
return (float)Math.sqrt(value);
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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 android.view;
import com.android.layoutlib.bridge.android.BridgeInflater;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.util.AttributeSet;
import java.io.IOException;
/**
* Delegate used to provide new implementation of a select few methods of {@link LayoutInflater}
*
* Through the layoutlib_create tool, the original methods of LayoutInflater have been replaced
* by calls to methods of the same name in this delegate class.
*
*/
public class LayoutInflater_Delegate {
/**
* Recursive method used to descend down the xml hierarchy and instantiate
* views, instantiate their children, and then call onFinishInflate().
*/
@LayoutlibDelegate
/*package*/ static void rInflate(LayoutInflater thisInflater,
XmlPullParser parser, View parent, final AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
if (finishInflate == false) {
// this is a merge rInflate!
if (thisInflater instanceof BridgeInflater) {
((BridgeInflater) thisInflater).setIsInMerge(true);
}
}
// ---- START DEFAULT IMPLEMENTATION.
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String name = parser.getName();
if (LayoutInflater.TAG_REQUEST_FOCUS.equals(name)) {
thisInflater.parseRequestFocus(parser, parent);
} else if (LayoutInflater.TAG_INCLUDE.equals(name)) {
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");
}
thisInflater.parseInclude(parser, parent, attrs);
} else if (LayoutInflater.TAG_MERGE.equals(name)) {
throw new InflateException("<merge /> must be the root element");
} else {
final View view = thisInflater.createViewFromTag(parent, name, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
thisInflater.rInflate(parser, view, attrs, true);
viewGroup.addView(view, params);
}
}
if (finishInflate) parent.onFinishInflate();
// ---- END DEFAULT IMPLEMENTATION.
if (finishInflate == false) {
// this is a merge rInflate!
if (thisInflater instanceof BridgeInflater) {
((BridgeInflater) thisInflater).setIsInMerge(false);
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (C) 2010 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.
@@ -14,27 +14,21 @@
* limitations under the License.
*/
package android.graphics;
package android.view;
import android.graphics.PorterDuff.Mode;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
public class PorterDuffXfermode extends Xfermode {
private final Mode mMode;
/**
* Delegate used to provide new implementation of a select few methods of {@link View}
*
* Through the layoutlib_create tool, the original methods of View have been replaced
* by calls to methods of the same name in this delegate class.
*
*/
public class View_Delegate {
/**
* Create an xfermode that uses the specified porter-duff mode.
*
* @param mode The porter-duff mode that is applied
*/
public PorterDuffXfermode(PorterDuff.Mode mode) {
mMode = mode;
@LayoutlibDelegate
/*package*/ static boolean isInEditMode(View thisView) {
return true;
}
//---------- Custom Methods
public PorterDuff.Mode getMode() {
return mMode;
}
//----------
}

View File

@@ -0,0 +1,74 @@
/*
* 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.internal.util;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate used to provide new implementation of a select few methods of {@link XmlUtils}
*
* Through the layoutlib_create tool, the original methods of XmlUtils have been replaced
* by calls to methods of the same name in this delegate class.
*
*/
public class XmlUtils_Delegate {
@LayoutlibDelegate
/*package*/ static final int convertValueToInt(CharSequence charSeq, int defaultValue) {
if (null == charSeq)
return defaultValue;
String nm = charSeq.toString();
// This code is copied from the original implementation. The issue is that
// The Dalvik libraries are able to handle Integer.parse("XXXXXXXX", 16) where XXXXXXX
// is > 80000000 but the Java VM cannot.
int sign = 1;
int index = 0;
int len = nm.length();
int base = 10;
if ('-' == nm.charAt(0)) {
sign = -1;
index++;
}
if ('0' == nm.charAt(index)) {
// Quick check for a zero by itself
if (index == (len - 1))
return 0;
char c = nm.charAt(index + 1);
if ('x' == c || 'X' == c) {
index += 2;
base = 16;
} else {
index++;
base = 8;
}
}
else if ('#' == nm.charAt(index)) {
index++;
base = 16;
}
return ((int)Long.parseLong(nm.substring(index), base)) * sign;
}
}

View File

@@ -41,24 +41,6 @@ public class BridgeConstants {
public final static String R = "com.android.internal.R";
public final static String PREFIX_ANDROID_RESOURCE_REF = "@android:";
public final static String PREFIX_RESOURCE_REF = "@";
public final static String PREFIX_ANDROID_THEME_REF = "?android:";
public final static String PREFIX_THEME_REF = "?";
public final static String PREFIX_ANDROID = "android:";
public final static String RES_STYLE = "style";
public final static String RES_ATTR = "attr";
public final static String RES_DIMEN = "dimen";
public final static String RES_DRAWABLE = "drawable";
public final static String RES_COLOR = "color";
public final static String RES_LAYOUT = "layout";
public final static String RES_STRING = "string";
public final static String RES_ID = "id";
public final static String REFERENCE_STYLE = RES_STYLE + "/";
public final static String REFERENCE_NULL = "@null";
public final static String MATCH_PARENT = "match_parent";
public final static String FILL_PARENT = "fill_parent";

View File

@@ -1,190 +0,0 @@
/*
* Copyright (C) 2009 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.layoutlib.bridge;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.IContentProvider;
import android.content.OperationApplicationException;
import android.content.res.AssetFileDescriptor;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.IBulkCursor;
import android.database.IContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import java.io.FileNotFoundException;
import java.util.ArrayList;
/**
* A mock content resolver for the LayoutLib Bridge.
* <p/>
* It won't serve any actual data but it's good enough for all
* the widgets which expect to have a content resolver available via
* {@link BridgeContext#getContentResolver()}.
*/
public class BridgeContentResolver extends ContentResolver {
private BridgeContentProvider mProvider = null;
public static final class BridgeContentProvider implements IContentProvider {
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> arg0)
throws RemoteException, OperationApplicationException {
// TODO Auto-generated method stub
return null;
}
public int bulkInsert(Uri arg0, ContentValues[] arg1) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
public IBulkCursor bulkQuery(Uri arg0, String[] arg1, String arg2, String[] arg3,
String arg4, IContentObserver arg5, CursorWindow arg6) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public Bundle call(String arg0, String arg1, Bundle arg2) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public int delete(Uri arg0, String arg1, String[] arg2) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
public String getType(Uri arg0) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public Uri insert(Uri arg0, ContentValues arg1) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public AssetFileDescriptor openAssetFile(Uri arg0, String arg1) throws RemoteException,
FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
public ParcelFileDescriptor openFile(Uri arg0, String arg1) throws RemoteException,
FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4)
throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3)
throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
public IBinder asBinder() {
// TODO Auto-generated method stub
return null;
}
}
public BridgeContentResolver(Context context) {
super(context);
}
@Override
public IContentProvider acquireProvider(Context c, String name) {
if (mProvider == null) {
mProvider = new BridgeContentProvider();
}
return mProvider;
}
@Override
public IContentProvider acquireExistingProvider(Context c, String name) {
if (mProvider == null) {
mProvider = new BridgeContentProvider();
}
return mProvider;
}
@Override
public boolean releaseProvider(IContentProvider icp) {
// ignore
return false;
}
/**
* Stub for the layoutlib bridge content resolver.
*/
@Override
public void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer) {
// pass
}
/**
* Stub for the layoutlib bridge content resolver.
*/
@Override
public void unregisterContentObserver(ContentObserver observer) {
// pass
}
/**
* Stub for the layoutlib bridge content resolver.
*/
@Override
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
// pass
}
/**
* Stub for the layoutlib bridge content resolver.
*/
@Override
public void startSync(Uri uri, Bundle extras) {
// pass
}
/**
* Stub for the layoutlib bridge content resolver.
*/
@Override
public void cancelSync(Uri uri) {
// pass
}
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright (C) 2010 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.layoutlib.bridge;
import com.android.ide.common.rendering.api.IAnimationListener;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import com.android.ide.common.rendering.api.RenderParams;
import com.android.ide.common.rendering.api.RenderSession;
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.api.ViewInfo;
import com.android.ide.common.rendering.api.Result.Status;
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Map;
/**
* An implementation of {@link RenderSession}.
*
* This is a pretty basic class that does almost nothing. All of the work is done in
* {@link RenderSessionImpl}.
*
*/
public class BridgeRenderSession extends RenderSession {
private final RenderSessionImpl mSession;
private Result mLastResult;
@Override
public Result getResult() {
return mLastResult;
}
@Override
public BufferedImage getImage() {
return mSession.getImage();
}
@Override
public boolean isAlphaChannelImage() {
return mSession.isAlphaChannelImage();
}
@Override
public List<ViewInfo> getRootViews() {
return mSession.getViewInfos();
}
@Override
public Map<String, String> getDefaultProperties(Object viewObject) {
return mSession.getDefaultProperties(viewObject);
}
@Override
public Result getProperty(Object objectView, String propertyName) {
// TODO Auto-generated method stub
return super.getProperty(objectView, propertyName);
}
@Override
public Result setProperty(Object objectView, String propertyName, String propertyValue) {
// TODO Auto-generated method stub
return super.setProperty(objectView, propertyName, propertyValue);
}
@Override
public Result getViewParent(Object viewObject) {
if (viewObject instanceof View) {
return Status.SUCCESS.createResult(((View)viewObject).getParent());
}
throw new IllegalArgumentException("viewObject is not a View");
}
@Override
public Result getViewIndex(Object viewObject) {
if (viewObject instanceof View) {
View view = (View) viewObject;
ViewParent parentView = view.getParent();
if (parentView instanceof ViewGroup) {
Status.SUCCESS.createResult(((ViewGroup) parentView).indexOfChild(view));
}
return Status.SUCCESS.createResult();
}
throw new IllegalArgumentException("viewObject is not a View");
}
@Override
public Result render(long timeout) {
try {
Bridge.prepareThread();
mLastResult = mSession.acquire(timeout);
if (mLastResult.isSuccess()) {
mLastResult = mSession.render(false /*freshRender*/);
}
} finally {
mSession.release();
Bridge.cleanupThread();
}
return mLastResult;
}
@Override
public Result animate(Object targetObject, String animationName,
boolean isFrameworkAnimation, IAnimationListener listener) {
try {
Bridge.prepareThread();
mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
if (mLastResult.isSuccess()) {
mLastResult = mSession.animate(targetObject, animationName, isFrameworkAnimation,
listener);
}
} finally {
mSession.release();
Bridge.cleanupThread();
}
return mLastResult;
}
@Override
public Result insertChild(Object parentView, ILayoutPullParser childXml, int index,
IAnimationListener listener) {
if (parentView instanceof ViewGroup == false) {
throw new IllegalArgumentException("parentView is not a ViewGroup");
}
try {
Bridge.prepareThread();
mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
if (mLastResult.isSuccess()) {
mLastResult = mSession.insertChild((ViewGroup) parentView, childXml, index,
listener);
}
} finally {
mSession.release();
Bridge.cleanupThread();
}
return mLastResult;
}
@Override
public Result moveChild(Object parentView, Object childView, int index,
Map<String, String> layoutParams, IAnimationListener listener) {
if (parentView instanceof ViewGroup == false) {
throw new IllegalArgumentException("parentView is not a ViewGroup");
}
if (childView instanceof View == false) {
throw new IllegalArgumentException("childView is not a View");
}
try {
Bridge.prepareThread();
mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
if (mLastResult.isSuccess()) {
mLastResult = mSession.moveChild((ViewGroup) parentView, (View) childView, index,
layoutParams, listener);
}
} finally {
mSession.release();
Bridge.cleanupThread();
}
return mLastResult;
}
@Override
public Result removeChild(Object childView, IAnimationListener listener) {
if (childView instanceof View == false) {
throw new IllegalArgumentException("childView is not a View");
}
try {
Bridge.prepareThread();
mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
if (mLastResult.isSuccess()) {
mLastResult = mSession.removeChild((View) childView, listener);
}
} finally {
mSession.release();
Bridge.cleanupThread();
}
return mLastResult;
}
@Override
public void dispose() {
}
/*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
mSession = scene;
if (scene != null) {
mSession.setScene(this);
}
mLastResult = lastResult;
}
}

View File

@@ -1,126 +0,0 @@
/*
* Copyright (C) 2008 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.layoutlib.bridge;
import com.android.layoutlib.api.ILayoutResult;
import java.awt.image.BufferedImage;
/**
* Implementation of {@link ILayoutResult}
*/
public final class LayoutResult implements ILayoutResult {
private final ILayoutViewInfo mRootView;
private final BufferedImage mImage;
private final int mSuccess;
private final String mErrorMessage;
/**
* Creates a {@link #SUCCESS} {@link ILayoutResult} with the specified params
* @param rootView
* @param image
*/
public LayoutResult(ILayoutViewInfo rootView, BufferedImage image) {
mSuccess = SUCCESS;
mErrorMessage = null;
mRootView = rootView;
mImage = image;
}
/**
* Creates a LayoutResult with a specific success code and associated message
* @param code
* @param message
*/
public LayoutResult(int code, String message) {
mSuccess = code;
mErrorMessage = message;
mRootView = null;
mImage = null;
}
public int getSuccess() {
return mSuccess;
}
public String getErrorMessage() {
return mErrorMessage;
}
public BufferedImage getImage() {
return mImage;
}
public ILayoutViewInfo getRootView() {
return mRootView;
}
/**
* Implementation of {@link ILayoutResult.ILayoutViewInfo}
*/
public static final class LayoutViewInfo implements ILayoutViewInfo {
private final Object mKey;
private final String mName;
private final int mLeft;
private final int mRight;
private final int mTop;
private final int mBottom;
private ILayoutViewInfo[] mChildren;
public LayoutViewInfo(String name, Object key, int left, int top, int right, int bottom) {
mName = name;
mKey = key;
mLeft = left;
mRight = right;
mTop = top;
mBottom = bottom;
}
public void setChildren(ILayoutViewInfo[] children) {
mChildren = children;
}
public ILayoutViewInfo[] getChildren() {
return mChildren;
}
public Object getViewKey() {
return mKey;
}
public String getName() {
return mName;
}
public int getLeft() {
return mLeft;
}
public int getTop() {
return mTop;
}
public int getRight() {
return mRight;
}
public int getBottom() {
return mBottom;
}
}
}

View File

@@ -1,107 +0,0 @@
/*
* Copyright (C) 2008 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.layoutlib.bridge;
import com.android.ninepatch.NinePatch;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
public class NinePatchDrawable extends Drawable {
private NinePatch m9Patch;
NinePatchDrawable(NinePatch ninePatch) {
m9Patch = ninePatch;
}
@Override
public int getMinimumWidth() {
return m9Patch.getWidth();
}
@Override
public int getMinimumHeight() {
return m9Patch.getHeight();
}
/**
* Return the intrinsic width of the underlying drawable object. Returns
* -1 if it has no intrinsic width, such as with a solid color.
*/
@Override
public int getIntrinsicWidth() {
return m9Patch.getWidth();
}
/**
* Return the intrinsic height of the underlying drawable object. Returns
* -1 if it has no intrinsic height, such as with a solid color.
*/
@Override
public int getIntrinsicHeight() {
return m9Patch.getHeight();
}
/**
* Return in padding the insets suggested by this Drawable for placing
* content inside the drawable's bounds. Positive values move toward the
* center of the Drawable (set Rect.inset). Returns true if this drawable
* actually has a padding, else false. When false is returned, the padding
* is always set to 0.
*/
@Override
public boolean getPadding(Rect padding) {
int[] padd = new int[4];
m9Patch.getPadding(padd);
padding.left = padd[0];
padding.top = padd[1];
padding.right = padd[2];
padding.bottom = padd[3];
return true;
}
@Override
public void draw(Canvas canvas) {
Rect r = getBounds();
m9Patch.draw(canvas.getGraphics2d(), r.left, r.top, r.width(), r.height());
return;
}
// ----------- Not implemented methods ---------------
@Override
public int getOpacity() {
// FIXME
return 0xFF;
}
@Override
public void setAlpha(int arg0) {
// FIXME !
}
@Override
public void setColorFilter(ColorFilter arg0) {
// FIXME
}
}

View File

@@ -1,67 +0,0 @@
/*
* Copyright (C) 2008 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.layoutlib.bridge;
import com.android.layoutlib.api.IResourceValue;
/**
* Basic implementation of IResourceValue.
*/
class ResourceValue implements IResourceValue {
private final String mType;
private final String mName;
private String mValue = null;
ResourceValue(String name) {
mType = null;
mName = name;
}
public ResourceValue(String type, String name, String value) {
mType = type;
mName = name;
mValue = value;
}
public String getType() {
return mType;
}
public final String getName() {
return mName;
}
public final String getValue() {
return mValue;
}
public final void setValue(String value) {
mValue = value;
}
public void replaceWith(ResourceValue value) {
mValue = value.mValue;
}
public boolean isFramework() {
// ResourceValue object created directly in the framework are used to describe
// non resolvable coming from the XML. Since they will never be cached (as they can't
// be a value pointing to a bitmap, or they'd be resolvable.), the return value deoes
// not matter.
return false;
}
}

View File

@@ -14,7 +14,9 @@
* limitations under the License.
*/
package com.android.layoutlib.bridge;
package com.android.layoutlib.bridge.android;
import com.android.layoutlib.bridge.Bridge;
import android.content.res.AssetManager;
@@ -28,7 +30,7 @@ public class BridgeAssetManager extends AssetManager {
* <p/>
* {@link Bridge} calls this method after setting up a new bridge.
*/
/*package*/ static AssetManager initSystem() {
/*package*/ public static AssetManager initSystem() {
if (!(AssetManager.sSystem instanceof BridgeAssetManager)) {
// Note that AssetManager() creates a system AssetManager and we override it
// with our BridgeAssetManager.
@@ -42,7 +44,7 @@ public class BridgeAssetManager extends AssetManager {
* Clears the static {@link AssetManager#sSystem} to make sure we don't leave objects
* around that would prevent us from unloading the library.
*/
/*package*/ static void clearSystem() {
public static void clearSystem() {
AssetManager.sSystem = null;
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2010 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.layoutlib.bridge.android;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentValues;
import android.content.IContentProvider;
import android.content.OperationApplicationException;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.IBulkCursor;
import android.database.IContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import java.io.FileNotFoundException;
import java.util.ArrayList;
/**
* Mock implementation of {@link IContentProvider}.
*
* TODO: never return null when the method is not supposed to. Return fake data instead.
*/
public final class BridgeContentProvider implements IContentProvider {
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> arg0)
throws RemoteException, OperationApplicationException {
// TODO Auto-generated method stub
return null;
}
public int bulkInsert(Uri arg0, ContentValues[] arg1) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
public IBulkCursor bulkQuery(Uri arg0, String[] arg1, String arg2, String[] arg3,
String arg4, IContentObserver arg5, CursorWindow arg6) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public Bundle call(String arg0, String arg1, Bundle arg2) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public int delete(Uri arg0, String arg1, String[] arg2) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
public String getType(Uri arg0) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public Uri insert(Uri arg0, ContentValues arg1) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public AssetFileDescriptor openAssetFile(Uri arg0, String arg1) throws RemoteException,
FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
public ParcelFileDescriptor openFile(Uri arg0, String arg1) throws RemoteException,
FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4)
throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3)
throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
public IBinder asBinder() {
// TODO Auto-generated method stub
return null;
}
public String[] getStreamTypes(Uri arg0, String arg1) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
public AssetFileDescriptor openTypedAssetFile(Uri arg0, String arg1, Bundle arg2)
throws RemoteException, FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (C) 2009 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.layoutlib.bridge.android;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentProvider;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
/**
* A mock content resolver for the LayoutLib Bridge.
* <p/>
* It won't serve any actual data but it's good enough for all
* the widgets which expect to have a content resolver available via
* {@link BridgeContext#getContentResolver()}.
*/
public class BridgeContentResolver extends ContentResolver {
private BridgeContentProvider mProvider = null;
public BridgeContentResolver(Context context) {
super(context);
}
@Override
public IContentProvider acquireProvider(Context c, String name) {
if (mProvider == null) {
mProvider = new BridgeContentProvider();
}
return mProvider;
}
@Override
public IContentProvider acquireExistingProvider(Context c, String name) {
if (mProvider == null) {
mProvider = new BridgeContentProvider();
}
return mProvider;
}
@Override
public boolean releaseProvider(IContentProvider icp) {
// ignore
return false;
}
/**
* Stub for the layoutlib bridge content resolver.
*/
@Override
public void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer) {
// pass
}
/**
* Stub for the layoutlib bridge content resolver.
*/
@Override
public void unregisterContentObserver(ContentObserver observer) {
// pass
}
/**
* Stub for the layoutlib bridge content resolver.
*/
@Override
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
// pass
}
/**
* Stub for the layoutlib bridge content resolver.
*/
@Override
public void startSync(Uri uri, Bundle extras) {
// pass
}
/**
* Stub for the layoutlib bridge content resolver.
*/
@Override
public void cancelSync(Uri uri) {
// pass
}
}

View File

@@ -14,13 +14,21 @@
* limitations under the License.
*/
package com.android.layoutlib.bridge;
package com.android.layoutlib.bridge.android;
import com.android.layoutlib.api.ILayoutLog;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
import com.android.layoutlib.api.IStyleResourceValue;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.StyleResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.impl.Stack;
import com.android.resources.ResourceType;
import com.android.util.Pair;
import android.app.Activity;
import android.app.Fragment;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -37,6 +45,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
@@ -47,7 +56,8 @@ import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.BridgeInflater;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import java.io.File;
@@ -57,81 +67,101 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;
/**
* Custom implementation of Context to handle non compiled resources.
* Custom implementation of Context/Activity to handle non compiled resources.
*/
public final class BridgeContext extends Context {
public final class BridgeContext extends Activity {
private final Resources mResources;
private final Theme mTheme;
private Resources mSystemResources;
private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
private final IStyleResourceValue mThemeValues;
private final Object mProjectKey;
private final Map<String, Map<String, IResourceValue>> mProjectResources;
private final Map<String, Map<String, IResourceValue>> mFrameworkResources;
private final Map<IStyleResourceValue, IStyleResourceValue> mStyleInheritanceMap;
private final DisplayMetrics mMetrics;
private final RenderResources mRenderResources;
private final ApplicationInfo mApplicationInfo;
// maps for dynamically generated id representing style objects (IStyleResourceValue)
private Map<Integer, IStyleResourceValue> mDynamicIdToStyleMap;
private Map<IStyleResourceValue, Integer> mStyleToDynamicIdMap;
private final Map<Object, Map<String, String>> mDefaultPropMaps =
new IdentityHashMap<Object, Map<String,String>>();
// maps for dynamically generated id representing style objects (StyleResourceValue)
private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap;
private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
private int mDynamicIdGenerator = 0x01030000; // Base id for framework R.style
// cache for TypedArray generated from IStyleResourceValue object
private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache;
private BridgeInflater mInflater;
private BridgeInflater mBridgeInflater;
private final IProjectCallback mProjectCallback;
private final ILayoutLog mLogger;
private BridgeContentResolver mContentResolver;
private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>();
/**
* @param projectKey An Object identifying the project. This is used for the cache mechanism.
* @param metrics the {@link DisplayMetrics}.
* @param themeName The name of the theme to use.
* @param projectResources the resources of the project. The map contains (String, map) pairs
* where the string is the type of the resource reference used in the layout file, and the
* map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
* map contains (String, {@link }) pairs where the key is the resource name,
* and the value is the resource value.
* @param frameworkResources the framework resources. The map contains (String, map) pairs
* where the string is the type of the resource reference used in the layout file, and the map
* contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
* contains (String, {@link ResourceValue}) pairs where the key is the resource name, and the
* value is the resource value.
* @param styleInheritanceMap
* @param customViewLoader
* @param projectCallback
* @param targetSdkVersion the targetSdkVersion of the application.
*/
public BridgeContext(Object projectKey, DisplayMetrics metrics,
IStyleResourceValue currentTheme,
Map<String, Map<String, IResourceValue>> projectResources,
Map<String, Map<String, IResourceValue>> frameworkResources,
Map<IStyleResourceValue, IStyleResourceValue> styleInheritanceMap,
IProjectCallback customViewLoader, ILayoutLog logger) {
RenderResources renderResources,
IProjectCallback projectCallback,
int targetSdkVersion) {
mProjectKey = projectKey;
mProjectCallback = customViewLoader;
mLogger = logger;
mMetrics = metrics;
mProjectCallback = projectCallback;
mRenderResources = renderResources;
mFragments.mCurState = Fragment.CREATED;
mFragments.mActivity = this;
mApplicationInfo = new ApplicationInfo();
mApplicationInfo.targetSdkVersion = targetSdkVersion;
}
/**
* Initializes the {@link Resources} singleton to be linked to this {@link Context}, its
* {@link DisplayMetrics}, {@link Configuration}, and {@link IProjectCallback}.
*
* @see #disposeResources()
*/
public void initResources() {
AssetManager assetManager = AssetManager.getSystem();
Configuration config = new Configuration();
AssetManager assetManager = BridgeAssetManager.initSystem();
mResources = BridgeResources.initSystem(
mSystemResources = BridgeResources.initSystem(
this,
assetManager,
metrics,
mMetrics,
config,
customViewLoader);
mProjectCallback);
mTheme = mSystemResources.newTheme();
}
mTheme = mResources.newTheme();
mThemeValues = currentTheme;
mProjectResources = projectResources;
mFrameworkResources = frameworkResources;
mStyleInheritanceMap = styleInheritanceMap;
/**
* Disposes the {@link Resources} singleton.
*/
public void disposeResources() {
BridgeResources.disposeSystem();
}
public void setBridgeInflater(BridgeInflater inflater) {
mInflater = inflater;
mBridgeInflater = inflater;
}
public void addViewKey(View view, Object viewKey) {
@@ -146,19 +176,112 @@ public final class BridgeContext extends Context {
return mProjectKey;
}
public DisplayMetrics getMetrics() {
return mMetrics;
}
public IProjectCallback getProjectCallback() {
return mProjectCallback;
}
public ILayoutLog getLogger() {
return mLogger;
public RenderResources getRenderResources() {
return mRenderResources;
}
public Map<String, String> getDefaultPropMap(Object key) {
return mDefaultPropMaps.get(key);
}
/**
* Adds a parser to the stack.
* @param parser the parser to add.
*/
public void pushParser(BridgeXmlBlockParser parser) {
mParserStack.push(parser);
}
/**
* Removes the parser at the top of the stack
*/
public void popParser() {
mParserStack.pop();
}
/**
* Returns the current parser at the top the of the stack.
* @return a parser or null.
*/
public BridgeXmlBlockParser getCurrentParser() {
return mParserStack.peek();
}
/**
* Returns the previous parser.
* @return a parser or null if there isn't any previous parser
*/
public BridgeXmlBlockParser getPreviousParser() {
if (mParserStack.size() < 2) {
return null;
}
return mParserStack.get(mParserStack.size() - 2);
}
public boolean resolveThemeAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resid);
if (resourceInfo == null) {
resourceInfo = mProjectCallback.resolveResourceId(resid);
}
if (resourceInfo == null) {
return false;
}
ResourceValue value = mRenderResources.findItemInTheme(resourceInfo.getSecond());
if (resolveRefs) {
value = mRenderResources.resolveResValue(value);
}
// check if this is a style resource
if (value instanceof StyleResourceValue) {
// get the id that will represent this style.
outValue.resourceId = getDynamicIdByStyle((StyleResourceValue)value);
return true;
}
int a;
// if this is a framework value.
if (value.isFramework()) {
// look for idName in the android R classes.
// use 0 a default res value as it's not a valid id value.
a = getFrameworkResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
} else {
// look for idName in the project R class.
// use 0 a default res value as it's not a valid id value.
a = getProjectResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
}
if (a != 0) {
outValue.resourceId = a;
return true;
}
return false;
}
// ------------- Activity Methods
@Override
public LayoutInflater getLayoutInflater() {
return mBridgeInflater;
}
// ------------ Context methods
@Override
public Resources getResources() {
return mResources;
return mSystemResources;
}
@Override
@@ -174,7 +297,7 @@ public final class BridgeContext extends Context {
@Override
public Object getSystemService(String service) {
if (LAYOUT_INFLATER_SERVICE.equals(service)) {
return mInflater;
return mBridgeInflater;
}
// AutoCompleteTextView and MultiAutoCompleteTextView want a window
@@ -183,20 +306,25 @@ public final class BridgeContext extends Context {
return null;
}
// needed by SearchView
if (INPUT_METHOD_SERVICE.equals(service)) {
return null;
}
throw new UnsupportedOperationException("Unsupported Service: " + service);
}
@Override
public final TypedArray obtainStyledAttributes(int[] attrs) {
return createStyleBasedTypedArray(mThemeValues, attrs);
return createStyleBasedTypedArray(mRenderResources.getCurrentTheme(), attrs);
}
@Override
public final TypedArray obtainStyledAttributes(int resid, int[] attrs)
throws Resources.NotFoundException {
// get the IStyleResourceValue based on the resId;
IStyleResourceValue style = getStyleByDynamicId(resid);
// get the StyleResourceValue based on the resId;
StyleResourceValue style = getStyleByDynamicId(resid);
if (style == null) {
throw new Resources.NotFoundException();
@@ -241,65 +369,130 @@ public final class BridgeContext extends Context {
public TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs,
int defStyleAttr, int defStyleRes) {
Map<String, String> defaultPropMap = null;
boolean isPlatformFile = true;
// Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java
BridgeXmlBlockParser parser = null;
if (set instanceof BridgeXmlBlockParser) {
BridgeXmlBlockParser parser = null;
parser = (BridgeXmlBlockParser)set;
isPlatformFile = parser.isPlatformFile();
Object key = parser.getViewCookie();
if (key != null) {
defaultPropMap = mDefaultPropMaps.get(key);
if (defaultPropMap == null) {
defaultPropMap = new HashMap<String, String>();
mDefaultPropMaps.put(key, defaultPropMap);
}
}
} else if (set instanceof BridgeLayoutParamsMapAttributes) {
// this is only for temp layout params generated dynamically, so this is never
// platform content.
isPlatformFile = false;
} else if (set != null) { // null parser is ok
// really this should not be happening since its instantiated in Bridge
mLogger.error("Parser is not a BridgeXmlBlockParser!");
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
"Parser is not a BridgeXmlBlockParser!", null /*data*/);
return null;
}
boolean[] frameworkAttributes = new boolean[1];
TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes);
BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length,
parser != null ? parser.isPlatformFile() : true);
BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
isPlatformFile);
// resolve the defStyleAttr value into a IStyleResourceValue
IStyleResourceValue defStyleValues = null;
StyleResourceValue defStyleValues = null;
// look for a custom style.
String customStyle = null;
if (parser != null) {
customStyle = parser.getAttributeValue(null /* namespace*/, "style");
if (set != null) {
customStyle = set.getAttributeValue(null /* namespace*/, "style");
}
if (customStyle != null) {
IResourceValue item = findResValue(customStyle, false /*forceFrameworkOnly*/);
ResourceValue item = mRenderResources.findResValue(customStyle,
false /*forceFrameworkOnly*/);
if (item instanceof IStyleResourceValue) {
defStyleValues = (IStyleResourceValue)item;
// resolve it in case it links to something else
item = mRenderResources.resolveResValue(item);
if (item instanceof StyleResourceValue) {
defStyleValues = (StyleResourceValue)item;
}
}
if (defStyleValues == null && defStyleAttr != 0) {
// get the name from the int.
String defStyleName = searchAttr(defStyleAttr);
if (defStyleValues == null) {
if (defStyleAttr != 0) {
// get the name from the int.
String defStyleName = searchAttr(defStyleAttr);
// look for the style in the current theme, and its parent:
if (mThemeValues != null) {
IResourceValue item = findItemInStyle(mThemeValues, defStyleName);
if (defaultPropMap != null) {
defaultPropMap.put("style", defStyleName);
}
// look for the style in the current theme, and its parent:
ResourceValue item = mRenderResources.findItemInTheme(defStyleName);
if (item != null) {
// item is a reference to a style entry. Search for it.
item = findResValue(item.getValue(), false /*forceFrameworkOnly*/);
item = mRenderResources.findResValue(item.getValue(),
false /*forceFrameworkOnly*/);
if (item instanceof IStyleResourceValue) {
defStyleValues = (IStyleResourceValue)item;
if (item instanceof StyleResourceValue) {
defStyleValues = (StyleResourceValue)item;
}
} else {
// TODO: log the error properly
System.out.println("Failed to find defStyle: " + defStyleName);
Bridge.getLog().error(null,
String.format(
"Failed to find style '%s' in current theme", defStyleName),
null /*data*/);
}
} else if (defStyleRes != 0) {
Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
if (value == null) {
value = mProjectCallback.resolveResourceId(defStyleRes);
}
if (value != null) {
if (value.getFirst() == ResourceType.STYLE) {
// look for the style in the current theme, and its parent:
ResourceValue item = mRenderResources.findItemInTheme(value.getSecond());
if (item != null) {
if (item instanceof StyleResourceValue) {
if (defaultPropMap != null) {
defaultPropMap.put("style", item.getName());
}
defStyleValues = (StyleResourceValue)item;
}
} else {
Bridge.getLog().error(null,
String.format(
"Style with id 0x%x (resolved to '%s') does not exist.",
defStyleRes, value.getSecond()),
null /*data*/);
}
} else {
Bridge.getLog().error(null,
String.format(
"Resouce id 0x%x is not of type STYLE (instead %s)",
defStyleRes, value.getFirst().toString()),
null /*data*/);
}
} else {
Bridge.getLog().error(null,
String.format(
"Failed to find style with id 0x%x in current theme",
defStyleRes),
null /*data*/);
}
}
}
if (defStyleRes != 0) {
// FIXME: See what we need to do with this.
throw new UnsupportedOperationException();
}
String namespace = BridgeConstants.NS_RESOURCES;
if (frameworkAttributes[0] == false) {
// need to use the application namespace
@@ -312,37 +505,43 @@ public final class BridgeContext extends Context {
String name = styleAttribute.getValue();
String value = null;
if (parser != null) {
value = parser.getAttributeValue(namespace, name);
if (set != null) {
value = set.getAttributeValue(namespace, name);
}
// if there's no direct value for this attribute in the XML, we look for default
// values in the widget defStyle, and then in the theme.
if (value == null) {
IResourceValue resValue = null;
ResourceValue resValue = null;
// look for the value in the defStyle first (and its parent if needed)
if (defStyleValues != null) {
resValue = findItemInStyle(defStyleValues, name);
resValue = mRenderResources.findItemInStyle(defStyleValues, name);
}
// if the item is not present in the defStyle, we look in the main theme (and
// its parent themes)
if (resValue == null && mThemeValues != null) {
resValue = findItemInStyle(mThemeValues, name);
if (resValue == null) {
resValue = mRenderResources.findItemInTheme(name);
}
// if we found a value, we make sure this doesn't reference another value.
// So we resolve it.
if (resValue != null) {
resValue = resolveResValue(resValue);
// put the first default value, before the resolution.
if (defaultPropMap != null) {
defaultPropMap.put(name, resValue.getValue());
}
resValue = mRenderResources.resolveResValue(resValue);
}
ta.bridgeSetValue(index, name, resValue);
} else {
// there is a value in the XML, but we need to resolve it in case it's
// referencing another resource or a theme value.
ta.bridgeSetValue(index, name, resolveValue(null, name, value));
ta.bridgeSetValue(index, name,
mRenderResources.resolveValue(null, name, value, isPlatformFile));
}
}
}
@@ -365,11 +564,11 @@ public final class BridgeContext extends Context {
* values found in the given style.
* @see #obtainStyledAttributes(int, int[])
*/
private BridgeTypedArray createStyleBasedTypedArray(IStyleResourceValue style, int[] attrs)
private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs)
throws Resources.NotFoundException {
TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, null);
BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length,
BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
false /* platformResourceFlag */);
// loop through all the values in the style map, and init the TypedArray with
@@ -380,10 +579,10 @@ public final class BridgeContext extends Context {
String name = styleAttribute.getValue();
// get the value from the style, or its parent styles.
IResourceValue resValue = findItemInStyle(style, name);
ResourceValue resValue = mRenderResources.findItemInStyle(style, name);
// resolve it to make sure there are no references left.
ta.bridgeSetValue(index, name, resolveResValue(resValue));
ta.bridgeSetValue(index, name, mRenderResources.resolveResValue(resValue));
}
ta.sealArray();
@@ -392,274 +591,6 @@ public final class BridgeContext extends Context {
}
/**
* Resolves the value of a resource, if the value references a theme or resource value.
* <p/>
* This method ensures that it returns a {@link IResourceValue} object that does not
* reference another resource.
* If the resource cannot be resolved, it returns <code>null</code>.
* <p/>
* If a value that does not need to be resolved is given, the method will return a new
* instance of IResourceValue that contains the input value.
*
* @param type the type of the resource
* @param name the name of the attribute containing this value.
* @param value the resource value, or reference to resolve
* @return the resolved resource value or <code>null</code> if it failed to resolve it.
*/
private IResourceValue resolveValue(String type, String name, String value) {
if (value == null) {
return null;
}
// get the IResourceValue referenced by this value
IResourceValue resValue = findResValue(value, false /*forceFrameworkOnly*/);
// if resValue is null, but value is not null, this means it was not a reference.
// we return the name/value wrapper in a IResourceValue
if (resValue == null) {
return new ResourceValue(type, name, value);
}
// we resolved a first reference, but we need to make sure this isn't a reference also.
return resolveResValue(resValue);
}
/**
* Returns the {@link IResourceValue} referenced by the value of <var>value</var>.
* <p/>
* This method ensures that it returns a {@link IResourceValue} object that does not
* reference another resource.
* If the resource cannot be resolved, it returns <code>null</code>.
* <p/>
* If a value that does not need to be resolved is given, the method will return the input
* value.
*
* @param value the value containing the reference to resolve.
* @return a {@link IResourceValue} object or <code>null</code>
*/
IResourceValue resolveResValue(IResourceValue value) {
if (value == null) {
return null;
}
// if the resource value is a style, we simply return it.
if (value instanceof IStyleResourceValue) {
return value;
}
// else attempt to find another IResourceValue referenced by this one.
IResourceValue resolvedValue = findResValue(value.getValue(), value.isFramework());
// if the value did not reference anything, then we simply return the input value
if (resolvedValue == null) {
return value;
}
// otherwise, we attempt to resolve this new value as well
return resolveResValue(resolvedValue);
}
/**
* Searches for, and returns a {@link IResourceValue} by its reference.
* <p/>
* The reference format can be:
* <pre>@resType/resName</pre>
* <pre>@android:resType/resName</pre>
* <pre>@resType/android:resName</pre>
* <pre>?resType/resName</pre>
* <pre>?android:resType/resName</pre>
* <pre>?resType/android:resName</pre>
* Any other string format will return <code>null</code>.
* <p/>
* The actual format of a reference is <pre>@[namespace:]resType/resName</pre> but this method
* only support the android namespace.
*
* @param reference the resource reference to search for.
* @param forceFrameworkOnly if true all references are considered to be toward framework
* resource even if the reference does not include the android: prefix.
* @return a {@link IResourceValue} or <code>null</code>.
*/
IResourceValue findResValue(String reference, boolean forceFrameworkOnly) {
if (reference == null) {
return null;
}
if (reference.startsWith(BridgeConstants.PREFIX_THEME_REF)) {
// no theme? no need to go further!
if (mThemeValues == null) {
return null;
}
boolean frameworkOnly = false;
// eleminate the prefix from the string
if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_THEME_REF)) {
frameworkOnly = true;
reference = reference.substring(BridgeConstants.PREFIX_ANDROID_THEME_REF.length());
} else {
reference = reference.substring(BridgeConstants.PREFIX_THEME_REF.length());
}
// at this point, value can contain type/name (drawable/foo for instance).
// split it to make sure.
String[] segments = reference.split("\\/");
// we look for the referenced item name.
String referenceName = null;
if (segments.length == 2) {
// there was a resType in the reference. If it's attr, we ignore it
// else, we assert for now.
if (BridgeConstants.RES_ATTR.equals(segments[0])) {
referenceName = segments[1];
} else {
// At this time, no support for ?type/name where type is not "attr"
return null;
}
} else {
// it's just an item name.
referenceName = segments[0];
}
// now we look for android: in the referenceName in order to support format
// such as: ?attr/android:name
if (referenceName.startsWith(BridgeConstants.PREFIX_ANDROID)) {
frameworkOnly = true;
referenceName = referenceName.substring(BridgeConstants.PREFIX_ANDROID.length());
}
// Now look for the item in the theme, starting with the current one.
if (frameworkOnly) {
// FIXME for now we do the same as if it didn't specify android:
return findItemInStyle(mThemeValues, referenceName);
}
return findItemInStyle(mThemeValues, referenceName);
} else if (reference.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
boolean frameworkOnly = false;
// check for the specific null reference value.
if (BridgeConstants.REFERENCE_NULL.equals(reference)) {
return null;
}
// Eliminate the prefix from the string.
if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_RESOURCE_REF)) {
frameworkOnly = true;
reference = reference.substring(
BridgeConstants.PREFIX_ANDROID_RESOURCE_REF.length());
} else {
reference = reference.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
}
// at this point, value contains type/[android:]name (drawable/foo for instance)
String[] segments = reference.split("\\/");
// now we look for android: in the resource name in order to support format
// such as: @drawable/android:name
if (segments[1].startsWith(BridgeConstants.PREFIX_ANDROID)) {
frameworkOnly = true;
segments[1] = segments[1].substring(BridgeConstants.PREFIX_ANDROID.length());
}
return findResValue(segments[0], segments[1],
forceFrameworkOnly ? true :frameworkOnly);
}
// Looks like the value didn't reference anything. Return null.
return null;
}
/**
* Searches for, and returns a {@link IResourceValue} by its name, and type.
* @param resType the type of the resource
* @param resName the name of the resource
* @param frameworkOnly if <code>true</code>, the method does not search in the
* project resources
*/
private IResourceValue findResValue(String resType, String resName, boolean frameworkOnly) {
// map of IResouceValue for the given type
Map<String, IResourceValue> typeMap;
// if allowed, search in the project resources first.
if (frameworkOnly == false) {
typeMap = mProjectResources.get(resType);
if (typeMap != null) {
IResourceValue item = typeMap.get(resName);
if (item != null) {
return item;
}
}
}
// now search in the framework resources.
typeMap = mFrameworkResources.get(resType);
if (typeMap != null) {
IResourceValue item = typeMap.get(resName);
if (item != null) {
return item;
}
}
// didn't find the resource anywhere.
return null;
}
/**
* Returns a framework resource by type and name. The returned resource is resolved.
* @param resourceType the type of the resource
* @param resourceName the name of the resource
*/
public IResourceValue getFrameworkResource(String resourceType, String resourceName) {
return getResource(resourceType, resourceName, mFrameworkResources);
}
/**
* Returns a project resource by type and name. The returned resource is resolved.
* @param resourceType the type of the resource
* @param resourceName the name of the resource
*/
public IResourceValue getProjectResource(String resourceType, String resourceName) {
return getResource(resourceType, resourceName, mProjectResources);
}
IResourceValue getResource(String resourceType, String resourceName,
Map<String, Map<String, IResourceValue>> resourceRepository) {
Map<String, IResourceValue> typeMap = resourceRepository.get(resourceType);
if (typeMap != null) {
IResourceValue item = typeMap.get(resourceName);
if (item != null) {
item = resolveResValue(item);
return item;
}
}
// didn't find the resource anywhere.
return null;
}
/**
* Returns the {@link IResourceValue} matching a given name in a given style. If the
* item is not directly available in the style, the method looks in its parent style.
* @param style the style to search in
* @param itemName the name of the item to search for.
* @return the {@link IResourceValue} object or <code>null</code>
*/
IResourceValue findItemInStyle(IStyleResourceValue style, String itemName) {
IResourceValue item = style.findItem(itemName);
// if we didn't find it, we look in the parent style (if applicable)
if (item == null && mStyleInheritanceMap != null) {
IStyleResourceValue parentStyle = mStyleInheritanceMap.get(style);
if (parentStyle != null) {
return findItemInStyle(parentStyle, itemName);
}
}
return item;
}
/**
* The input int[] attrs is one of com.android.internal.R.styleable fields where the name
* of the field is the style being referenced and the array contains one index per attribute.
@@ -675,14 +606,14 @@ public final class BridgeContext extends Context {
*/
private TreeMap<Integer,String> searchAttrs(int[] attrs, boolean[] outFrameworkFlag) {
// get the name of the array from the framework resources
String arrayName = Bridge.resolveResourceValue(attrs);
String arrayName = Bridge.resolveResourceId(attrs);
if (arrayName != null) {
// if we found it, get the name of each of the int in the array.
TreeMap<Integer,String> attributes = new TreeMap<Integer, String>();
for (int i = 0 ; i < attrs.length ; i++) {
String[] info = Bridge.resolveResourceValue(attrs[i]);
Pair<ResourceType, String> info = Bridge.resolveResourceId(attrs[i]);
if (info != null) {
attributes.put(i, info[0]);
attributes.put(i, info.getSecond());
} else {
// FIXME Not sure what we should be doing here...
attributes.put(i, null);
@@ -698,13 +629,13 @@ public final class BridgeContext extends Context {
// if the name was not found in the framework resources, look in the project
// resources
arrayName = mProjectCallback.resolveResourceValue(attrs);
arrayName = mProjectCallback.resolveResourceId(attrs);
if (arrayName != null) {
TreeMap<Integer,String> attributes = new TreeMap<Integer, String>();
for (int i = 0 ; i < attrs.length ; i++) {
String[] info = mProjectCallback.resolveResourceValue(attrs[i]);
Pair<ResourceType, String> info = mProjectCallback.resolveResourceId(attrs[i]);
if (info != null) {
attributes.put(i, info[0]);
attributes.put(i, info.getSecond());
} else {
// FIXME Not sure what we should be doing here...
attributes.put(i, null);
@@ -729,24 +660,24 @@ public final class BridgeContext extends Context {
* if nothing is found.
*/
public String searchAttr(int attr) {
String[] info = Bridge.resolveResourceValue(attr);
Pair<ResourceType, String> info = Bridge.resolveResourceId(attr);
if (info != null) {
return info[0];
return info.getSecond();
}
info = mProjectCallback.resolveResourceValue(attr);
info = mProjectCallback.resolveResourceId(attr);
if (info != null) {
return info[0];
return info.getSecond();
}
return null;
}
int getDynamicIdByStyle(IStyleResourceValue resValue) {
int getDynamicIdByStyle(StyleResourceValue resValue) {
if (mDynamicIdToStyleMap == null) {
// create the maps.
mDynamicIdToStyleMap = new HashMap<Integer, IStyleResourceValue>();
mStyleToDynamicIdMap = new HashMap<IStyleResourceValue, Integer>();
mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>();
mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>();
}
// look for an existing id
@@ -764,7 +695,7 @@ public final class BridgeContext extends Context {
return id;
}
private IStyleResourceValue getStyleByDynamicId(int i) {
private StyleResourceValue getStyleByDynamicId(int i) {
if (mDynamicIdToStyleMap != null) {
return mDynamicIdToStyleMap.get(i);
}
@@ -772,8 +703,8 @@ public final class BridgeContext extends Context {
return null;
}
int getFrameworkIdValue(String idName, int defValue) {
Integer value = Bridge.getResourceValue(BridgeConstants.RES_ID, idName);
int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) {
Integer value = Bridge.getResourceId(resType, resName);
if (value != null) {
return value.intValue();
}
@@ -781,9 +712,9 @@ public final class BridgeContext extends Context {
return defValue;
}
int getProjectIdValue(String idName, int defValue) {
int getProjectResourceValue(ResourceType resType, String resName, int defValue) {
if (mProjectCallback != null) {
Integer value = mProjectCallback.getResourceValue(BridgeConstants.RES_ID, idName);
Integer value = mProjectCallback.getResourceId(resType, resName);
if (value != null) {
return value.intValue();
}
@@ -1000,7 +931,7 @@ public final class BridgeContext extends Context {
@Override
public ApplicationInfo getApplicationInfo() {
return new ApplicationInfo();
return mApplicationInfo;
}
@Override
@@ -1043,25 +974,27 @@ public final class BridgeContext extends Context {
}
@SuppressWarnings("unused")
@Override
public FileInputStream openFileInput(String arg0)
throws FileNotFoundException {
public FileInputStream openFileInput(String arg0) throws FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
@SuppressWarnings("unused")
@Override
public FileOutputStream openFileOutput(String arg0, int arg1)
throws FileNotFoundException {
public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
@Override
public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) {
// TODO Auto-generated method stub
return null;
}
@Override
public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
CursorFactory arg2) {
CursorFactory arg2, DatabaseErrorHandler arg3) {
// TODO Auto-generated method stub
return null;
}
@@ -1142,14 +1075,12 @@ public final class BridgeContext extends Context {
}
@SuppressWarnings("unused")
@Override
public void setWallpaper(Bitmap arg0) throws IOException {
// TODO Auto-generated method stub
}
@SuppressWarnings("unused")
@Override
public void setWallpaper(InputStream arg0) throws IOException {
// TODO Auto-generated method stub
@@ -1204,4 +1135,15 @@ public final class BridgeContext extends Context {
public Context getApplicationContext() {
throw new UnsupportedOperationException();
}
@Override
public void startActivities(Intent[] arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean isRestricted() {
return false;
}
}

View File

@@ -14,36 +14,42 @@
* limitations under the License.
*/
package android.view;
package com.android.layoutlib.bridge.android;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.rendering.api.MergeCookie;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.BridgeContext;
import com.android.layoutlib.bridge.BridgeXmlBlockParser;
import com.android.resources.ResourceType;
import com.android.util.Pair;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import android.content.Context;
import android.util.AttributeSet;
import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.io.File;
import java.io.FileReader;
/**
* Custom implementation of {@link LayoutInflater} to handle custom views.
* Custom implementation of {@link LayoutInflater} to handle custom views.
*/
public final class BridgeInflater extends LayoutInflater {
private final IProjectCallback mProjectCallback;
private boolean mIsInMerge = false;
/**
* List of class prefixes which are tried first by default.
* <p/>
* This should match the list in com.android.internal.policy.impl.PhoneLayoutInflater.
*/
*/
private static final String[] sClassPrefixList = {
"android.widget.",
"android.webkit."
@@ -53,10 +59,10 @@ public final class BridgeInflater extends LayoutInflater {
super(original, newContext);
mProjectCallback = null;
}
/**
* Instantiate a new BridgeInflater with an {@link IProjectCallback} object.
*
*
* @param context The Android application context.
* @param projectCallback the {@link IProjectCallback} object.
*/
@@ -82,7 +88,7 @@ public final class BridgeInflater extends LayoutInflater {
// Ignore. We'll try again using the base class below.
}
}
// Next try using the parent loader. This will most likely only work for
// fully-qualified class names.
try {
@@ -92,7 +98,7 @@ public final class BridgeInflater extends LayoutInflater {
} catch (ClassNotFoundException e) {
// Ignore. We'll try again using the custom view loader below.
}
// Finally try again using the custom view loader
try {
if (view == null) {
@@ -109,17 +115,17 @@ public final class BridgeInflater extends LayoutInflater {
ClassNotFoundException exception = new ClassNotFoundException("onCreateView", e);
throw exception;
}
setupViewInContext(view, attrs);
return view;
}
@Override
public View createViewFromTag(String name, AttributeSet attrs) {
public View createViewFromTag(View parent, String name, AttributeSet attrs) {
View view = null;
try {
view = super.createViewFromTag(name, attrs);
view = super.createViewFromTag(parent, name, attrs);
} catch (InflateException e) {
// try to load the class from using the custom view loader
try {
@@ -128,7 +134,7 @@ public final class BridgeInflater extends LayoutInflater {
// Wrap the real exception in an InflateException so that the calling
// method can deal with it.
InflateException exception = new InflateException();
if (e2.getClass().equals(ClassNotFoundException.class) == false) {
if (e2.getClass().equals(ClassNotFoundException.class) == false) {
exception.initCause(e2);
} else {
exception.initCause(e);
@@ -136,30 +142,30 @@ public final class BridgeInflater extends LayoutInflater {
throw exception;
}
}
setupViewInContext(view, attrs);
return view;
}
@Override
public View inflate(int resource, ViewGroup root) {
Context context = getContext();
if (context instanceof BridgeContext) {
BridgeContext bridgeContext = (BridgeContext)context;
IResourceValue value = null;
String[] layoutInfo = Bridge.resolveResourceValue(resource);
ResourceValue value = null;
Pair<ResourceType, String> layoutInfo = Bridge.resolveResourceId(resource);
if (layoutInfo != null) {
value = bridgeContext.getFrameworkResource(BridgeConstants.RES_LAYOUT,
layoutInfo[0]);
value = bridgeContext.getRenderResources().getFrameworkResource(
ResourceType.LAYOUT, layoutInfo.getSecond());
} else {
layoutInfo = mProjectCallback.resolveResourceValue(resource);
layoutInfo = mProjectCallback.resolveResourceId(resource);
if (layoutInfo != null) {
value = bridgeContext.getProjectResource(BridgeConstants.RES_LAYOUT,
layoutInfo[0]);
value = bridgeContext.getRenderResources().getProjectResource(
ResourceType.LAYOUT, layoutInfo.getSecond());
}
}
@@ -170,21 +176,23 @@ public final class BridgeInflater extends LayoutInflater {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(f));
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
parser, bridgeContext, false);
return inflate(bridgeParser, root);
} catch (Exception e) {
bridgeContext.getLogger().error(e);
// return null below.
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
"Failed to parse file " + f.getAbsolutePath(), e, null /*data*/);
return null;
}
}
}
}
return null;
}
private View loadCustomView(String name, AttributeSet attrs) throws ClassNotFoundException,
Exception{
if (mProjectCallback != null) {
@@ -192,12 +200,12 @@ public final class BridgeInflater extends LayoutInflater {
if (name.equals("view")) {
name = attrs.getAttributeValue(null, "class");
}
mConstructorArgs[1] = attrs;
Object customView = mProjectCallback.loadView(name, mConstructorSignature,
mConstructorArgs);
if (customView instanceof View) {
return (View)customView;
}
@@ -205,21 +213,43 @@ public final class BridgeInflater extends LayoutInflater {
return null;
}
private void setupViewInContext(View view, AttributeSet attrs) {
if (getContext() instanceof BridgeContext) {
BridgeContext bc = (BridgeContext) getContext();
if (attrs instanceof BridgeXmlBlockParser) {
Object viewKey = ((BridgeXmlBlockParser) attrs).getViewKey();
BridgeXmlBlockParser parser = (BridgeXmlBlockParser) attrs;
// get the view key
Object viewKey = parser.getViewCookie();
// if there's no view key and the depth is 1 (ie this is the first tag), or 2
// (this is first item in included merge layout)
// look for a previous parser in the context, and check if this one has a viewkey.
int testDepth = mIsInMerge ? 2 : 1;
if (viewKey == null && parser.getDepth() == testDepth) {
BridgeXmlBlockParser previousParser = bc.getPreviousParser();
if (previousParser != null) {
viewKey = previousParser.getViewCookie();
}
}
if (viewKey != null) {
if (testDepth == 2) {
// include-merge case
viewKey = new MergeCookie(viewKey);
}
bc.addViewKey(view, viewKey);
}
}
}
}
public void setIsInMerge(boolean isInMerge) {
mIsInMerge = isInMerge;
}
@Override
public LayoutInflater cloneInContext(Context newContext) {
return new BridgeInflater(this, newContext);

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2010 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.layoutlib.bridge.android;
import com.android.layoutlib.bridge.BridgeConstants;
import android.util.AttributeSet;
import java.util.Map;
/**
* An implementation of the {@link AttributeSet} interface on top of a map of attribute in the form
* of (name, value).
*
* This is meant to be called only from {@link BridgeContext#obtainStyledAttributes(AttributeSet, int[], int, int)}
* in the case of LayoutParams and therefore isn't a full implementation.
*/
public class BridgeLayoutParamsMapAttributes implements AttributeSet {
private final Map<String, String> mAttributes;
public BridgeLayoutParamsMapAttributes(Map<String, String> attributes) {
mAttributes = attributes;
}
public String getAttributeValue(String namespace, String name) {
if (BridgeConstants.NS_RESOURCES.equals(namespace)) {
return mAttributes.get(name);
}
return null;
}
// ---- the following methods are not called from
// BridgeContext#obtainStyledAttributes(AttributeSet, int[], int, int)
// Should they ever be called, we'll just implement them on a need basis.
public int getAttributeCount() {
throw new UnsupportedOperationException();
}
public String getAttributeName(int index) {
throw new UnsupportedOperationException();
}
public String getAttributeValue(int index) {
throw new UnsupportedOperationException();
}
public String getPositionDescription() {
throw new UnsupportedOperationException();
}
public int getAttributeNameResource(int index) {
throw new UnsupportedOperationException();
}
public int getAttributeListValue(String namespace, String attribute,
String[] options, int defaultValue) {
throw new UnsupportedOperationException();
}
public boolean getAttributeBooleanValue(String namespace, String attribute,
boolean defaultValue) {
throw new UnsupportedOperationException();
}
public int getAttributeResourceValue(String namespace, String attribute,
int defaultValue) {
throw new UnsupportedOperationException();
}
public int getAttributeIntValue(String namespace, String attribute,
int defaultValue) {
throw new UnsupportedOperationException();
}
public int getAttributeUnsignedIntValue(String namespace, String attribute,
int defaultValue) {
throw new UnsupportedOperationException();
}
public float getAttributeFloatValue(String namespace, String attribute,
float defaultValue) {
throw new UnsupportedOperationException();
}
public int getAttributeListValue(int index,
String[] options, int defaultValue) {
throw new UnsupportedOperationException();
}
public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
throw new UnsupportedOperationException();
}
public int getAttributeResourceValue(int index, int defaultValue) {
throw new UnsupportedOperationException();
}
public int getAttributeIntValue(int index, int defaultValue) {
throw new UnsupportedOperationException();
}
public int getAttributeUnsignedIntValue(int index, int defaultValue) {
throw new UnsupportedOperationException();
}
public float getAttributeFloatValue(int index, float defaultValue) {
throw new UnsupportedOperationException();
}
public String getIdAttribute() {
throw new UnsupportedOperationException();
}
public String getClassAttribute() {
throw new UnsupportedOperationException();
}
public int getIdAttributeResourceValue(int defaultValue) {
throw new UnsupportedOperationException();
}
public int getStyleAttribute() {
throw new UnsupportedOperationException();
}
}

View File

@@ -14,10 +14,17 @@
* limitations under the License.
*/
package com.android.layoutlib.bridge;
package com.android.layoutlib.bridge.android;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.ninepatch.NinePatch;
import com.android.resources.ResourceType;
import com.android.util.Pair;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
@@ -51,6 +58,35 @@ public final class BridgeResources extends Resources {
private IProjectCallback mProjectCallback;
private boolean[] mPlatformResourceFlag = new boolean[1];
/**
* Simpler wrapper around FileInputStream. This is used when the input stream represent
* not a normal bitmap but a nine patch.
* This is useful when the InputStream is created in a method but used in another that needs
* to know whether this is 9-patch or not, such as BitmapFactory.
*/
public class NinePatchInputStream extends FileInputStream {
private boolean mFakeMarkSupport = true;
public NinePatchInputStream(File file) throws FileNotFoundException {
super(file);
}
@Override
public boolean markSupported() {
if (mFakeMarkSupport) {
// this is needed so that BitmapFactory doesn't wrap this in a BufferedInputStream.
return true;
}
return super.markSupported();
}
public void disableFakeMarkSupport() {
// disable fake mark support so that in case codec actually try to use them
// we don't lie to them.
mFakeMarkSupport = false;
}
}
/**
* This initializes the static field {@link Resources#mSystem} which is used
* by methods who get global resources using {@link Resources#getSystem()}.
@@ -64,21 +100,18 @@ public final class BridgeResources extends Resources {
DisplayMetrics metrics,
Configuration config,
IProjectCallback projectCallback) {
if (!(Resources.mSystem instanceof BridgeResources)) {
Resources.mSystem = new BridgeResources(context,
assets,
metrics,
config,
projectCallback);
}
return Resources.mSystem;
return Resources.mSystem = new BridgeResources(context,
assets,
metrics,
config,
projectCallback);
}
/**
* Clears the static {@link Resources#mSystem} to make sure we don't leave objects
* Disposes the static {@link Resources#mSystem} to make sure we don't leave objects
* around that would prevent us from unloading the library.
*/
/*package*/ static void clearSystem() {
/*package*/ static void disposeSystem() {
if (Resources.mSystem instanceof BridgeResources) {
((BridgeResources)(Resources.mSystem)).mContext = null;
((BridgeResources)(Resources.mSystem)).mProjectCallback = null;
@@ -97,22 +130,24 @@ public final class BridgeResources extends Resources {
return new BridgeTypedArray(this, mContext, numEntries, platformFile);
}
private IResourceValue getResourceValue(int id, boolean[] platformResFlag_out) {
private ResourceValue getResourceValue(int id, boolean[] platformResFlag_out) {
// first get the String related to this id in the framework
String[] resourceInfo = Bridge.resolveResourceValue(id);
Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
if (resourceInfo != null) {
platformResFlag_out[0] = true;
return mContext.getFrameworkResource(resourceInfo[1], resourceInfo[0]);
return mContext.getRenderResources().getFrameworkResource(
resourceInfo.getFirst(), resourceInfo.getSecond());
}
// didn't find a match in the framework? look in the project.
if (mProjectCallback != null) {
resourceInfo = mProjectCallback.resolveResourceValue(id);
resourceInfo = mProjectCallback.resolveResourceId(id);
if (resourceInfo != null) {
platformResFlag_out[0] = false;
return mContext.getProjectResource(resourceInfo[1], resourceInfo[0]);
return mContext.getRenderResources().getProjectResource(
resourceInfo.getFirst(), resourceInfo.getSecond());
}
}
@@ -121,10 +156,10 @@ public final class BridgeResources extends Resources {
@Override
public Drawable getDrawable(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
return ResourceHelper.getDrawable(value, mContext, value.isFramework());
return ResourceHelper.getDrawable(value, mContext);
}
// id was not found or not resolved. Throw a NotFoundException.
@@ -136,12 +171,14 @@ public final class BridgeResources extends Resources {
@Override
public int getColor(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
try {
return ResourceHelper.getColor(value.getValue());
} catch (NumberFormatException e) {
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e,
null /*data*/);
return 0;
}
}
@@ -155,14 +192,12 @@ public final class BridgeResources extends Resources {
@Override
public ColorStateList getColorStateList(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue resValue = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
try {
int color = ResourceHelper.getColor(value.getValue());
return ColorStateList.valueOf(color);
} catch (NumberFormatException e) {
return null;
if (resValue != null) {
ColorStateList stateList = ResourceHelper.getColorStateList(resValue, mContext);
if (stateList != null) {
return stateList;
}
}
@@ -175,7 +210,7 @@ public final class BridgeResources extends Resources {
@Override
public CharSequence getText(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
return value.getValue();
@@ -190,27 +225,76 @@ public final class BridgeResources extends Resources {
@Override
public XmlResourceParser getLayout(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
File xml = new File(value.getValue());
if (xml.isFile()) {
// we need to create a pull parser around the layout XML file, and then
// give that to our XmlBlockParser
try {
KXmlParser parser = new KXmlParser();
XmlPullParser parser = null;
try {
// check if the current parser can provide us with a custom parser.
BridgeXmlBlockParser currentParser = mContext.getCurrentParser();
if (currentParser != null) {
parser = currentParser.getParser(value.getName());
}
// create a new one manually if needed.
if (parser == null) {
File xml = new File(value.getValue());
if (xml.isFile()) {
// we need to create a pull parser around the layout XML file, and then
// give that to our XmlBlockParser
parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(xml));
}
}
if (parser != null) {
return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
}
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
"Failed to configure parser for " + value.getValue(), e, null /*data*/);
// we'll return null below.
} catch (FileNotFoundException e) {
// this shouldn't happen since we check above.
}
}
// id was not found or not resolved. Throw a NotFoundException.
throwException(id);
// this is not used since the method above always throws
return null;
}
@Override
public XmlResourceParser getAnimation(int id) throws NotFoundException {
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
XmlPullParser parser = null;
try {
File xml = new File(value.getValue());
if (xml.isFile()) {
// we need to create a pull parser around the layout XML file, and then
// give that to our XmlBlockParser
parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(xml));
return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
} catch (XmlPullParserException e) {
mContext.getLogger().error(e);
// we'll return null below.
} catch (FileNotFoundException e) {
// this shouldn't happen since we check above.
}
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
"Failed to configure parser for " + value.getValue(), e, null /*data*/);
// we'll return null below.
} catch (FileNotFoundException e) {
// this shouldn't happen since we check above.
}
}
// id was not found or not resolved. Throw a NotFoundException.
@@ -233,7 +317,7 @@ public final class BridgeResources extends Resources {
@Override
public float getDimension(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
@@ -262,7 +346,7 @@ public final class BridgeResources extends Resources {
@Override
public int getDimensionPixelOffset(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
@@ -284,7 +368,7 @@ public final class BridgeResources extends Resources {
@Override
public int getDimensionPixelSize(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
@@ -306,7 +390,7 @@ public final class BridgeResources extends Resources {
@Override
public int getInteger(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null && value.getValue() != null) {
String v = value.getValue();
@@ -361,7 +445,7 @@ public final class BridgeResources extends Resources {
@Override
public String getString(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null && value.getValue() != null) {
return value.getValue();
@@ -377,7 +461,7 @@ public final class BridgeResources extends Resources {
@Override
public void getValue(int id, TypedValue outValue, boolean resolveRefs)
throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
@@ -406,7 +490,7 @@ public final class BridgeResources extends Resources {
@Override
public XmlResourceParser getXml(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
@@ -470,16 +554,22 @@ public final class BridgeResources extends Resources {
@Override
public InputStream openRawResource(int id) throws NotFoundException {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
String path = value.getValue();
if (v != null) {
if (path != null) {
// check this is a file
File f = new File(value.getValue());
File f = new File(path);
if (f.isFile()) {
try {
// if it's a nine-patch return a custom input stream so that
// other methods (mainly bitmap factory) can detect it's a 9-patch
// and actually load it as a 9-patch instead of a normal bitmap
if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
return new NinePatchInputStream(f);
}
return new FileInputStream(f);
} catch (FileNotFoundException e) {
NotFoundException newE = new NotFoundException();
@@ -501,9 +591,17 @@ public final class BridgeResources extends Resources {
public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
getValue(id, value, true);
File f = new File(value.string.toString());
String path = value.string.toString();
File f = new File(path);
if (f.isFile()) {
try {
// if it's a nine-patch return a custom input stream so that
// other methods (mainly bitmap factory) can detect it's a 9-patch
// and actually load it as a 9-patch instead of a normal bitmap
if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
return new NinePatchInputStream(f);
}
return new FileInputStream(f);
} catch (FileNotFoundException e) {
NotFoundException exception = new NotFoundException();
@@ -527,18 +625,18 @@ public final class BridgeResources extends Resources {
*/
private void throwException(int id) throws NotFoundException {
// first get the String related to this id in the framework
String[] resourceInfo = Bridge.resolveResourceValue(id);
Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
// if the name is unknown in the framework, get it from the custom view loader.
if (resourceInfo == null && mProjectCallback != null) {
resourceInfo = mProjectCallback.resolveResourceValue(id);
resourceInfo = mProjectCallback.resolveResourceId(id);
}
String message = null;
if (resourceInfo != null) {
message = String.format(
"Could not find %1$s resource matching value 0x%2$X (resolved name: %3$s) in current configuration.",
resourceInfo[1], id, resourceInfo[0]);
resourceInfo.getFirst(), id, resourceInfo.getSecond());
} else {
message = String.format(
"Could not resolve resource value: 0x%1$X.", id);

View File

@@ -14,14 +14,21 @@
* limitations under the License.
*/
package com.android.layoutlib.bridge;
package com.android.layoutlib.bridge.android;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.StyleResourceValue;
import com.android.internal.util.XmlUtils;
import com.android.layoutlib.api.IResourceValue;
import com.android.layoutlib.api.IStyleResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.resources.ResourceType;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -33,39 +40,38 @@ import android.view.ViewGroup.LayoutParams;
import java.io.File;
import java.io.FileReader;
import java.util.Arrays;
import java.util.Map;
/**
* TODO: describe.
* Custom implementation of TypedArray to handle non compiled resources.
*/
public final class BridgeTypedArray extends TypedArray {
@SuppressWarnings("hiding")
private BridgeResources mResources;
private BridgeResources mBridgeResources;
private BridgeContext mContext;
@SuppressWarnings("hiding")
private IResourceValue[] mData;
private ResourceValue[] mResourceData;
private String[] mNames;
private final boolean mPlatformFile;
public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len,
boolean platformFile) {
super(null, null, null, 0);
mResources = resources;
mBridgeResources = resources;
mContext = context;
mPlatformFile = platformFile;
mData = new IResourceValue[len];
mResourceData = new ResourceValue[len];
mNames = new String[len];
}
/** A bridge-specific method that sets a value in the type array */
public void bridgeSetValue(int index, String name, IResourceValue value) {
mData[index] = value;
public void bridgeSetValue(int index, String name, ResourceValue value) {
mResourceData[index] = value;
mNames[index] = name;
}
/**
* Seals the array after all calls to {@link #bridgeSetValue(int, String, IResourceValue)} have
* Seals the array after all calls to {@link #bridgeSetValue(int, String, ResourceValue)} have
* been done.
* <p/>This allows to compute the list of non default values, permitting
* {@link #getIndexCount()} to return the proper value.
@@ -74,7 +80,7 @@ public final class BridgeTypedArray extends TypedArray {
// fills TypedArray.mIndices which is used to implement getIndexCount/getIndexAt
// first count the array size
int count = 0;
for (IResourceValue data : mData) {
for (ResourceValue data : mResourceData) {
if (data != null) {
count++;
}
@@ -86,8 +92,8 @@ public final class BridgeTypedArray extends TypedArray {
// fill the array with the indices.
int index = 1;
for (int i = 0 ; i < mData.length ; i++) {
if (mData[i] != null) {
for (int i = 0 ; i < mResourceData.length ; i++) {
if (mResourceData[i] != null) {
mIndices[index++] = i;
}
}
@@ -98,7 +104,7 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int length() {
return mData.length;
return mResourceData.length;
}
/**
@@ -106,7 +112,7 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public Resources getResources() {
return mResources;
return mBridgeResources;
}
/**
@@ -119,9 +125,9 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public CharSequence getText(int index) {
if (mData[index] != null) {
if (mResourceData[index] != null) {
// FIXME: handle styled strings!
return mData[index].getValue();
return mResourceData[index].getValue();
}
return null;
@@ -137,8 +143,8 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public String getString(int index) {
if (mData[index] != null) {
return mData[index].getValue();
if (mResourceData[index] != null) {
return mResourceData[index].getValue();
}
return null;
@@ -154,11 +160,11 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public boolean getBoolean(int index, boolean defValue) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return defValue;
}
String s = mData[index].getValue();
String s = mResourceData[index].getValue();
if (s != null) {
return XmlUtils.convertValueToBoolean(s, defValue);
}
@@ -176,11 +182,15 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getInt(int index, int defValue) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return defValue;
}
String s = mData[index].getValue();
String s = mResourceData[index].getValue();
if (RenderResources.REFERENCE_NULL.equals(s)) {
return defValue;
}
try {
return (s == null) ? defValue : XmlUtils.convertValueToInt(s, defValue);
@@ -204,9 +214,10 @@ public final class BridgeTypedArray extends TypedArray {
if (i != null) {
result |= i.intValue();
} else {
mContext.getLogger().warning(String.format(
"Unknown constant \"%s\" in attribute \"%2$s\"",
keyword, mNames[index]));
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format(
"\"%s\" in attribute \"%2$s\" is not a valid value",
keyword, mNames[index]), null /*data*/);
}
}
return result;
@@ -224,19 +235,20 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public float getFloat(int index, float defValue) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return defValue;
}
String s = mData[index].getValue();
String s = mResourceData[index].getValue();
if (s != null) {
try {
return Float.parseFloat(s);
} catch (NumberFormatException e) {
mContext.getLogger().warning(String.format(
"Unable to convert \"%s\" into a float in attribute \"%2$s\"",
s, mNames[index]));
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format(
"\"%s\" in attribute \"%2$s\" cannot be converted to float.",
s, mNames[index]), null /*data*/);
// we'll return the default value below.
}
@@ -258,19 +270,14 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getColor(int index, int defValue) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return defValue;
}
String s = mData[index].getValue();
try {
return ResourceHelper.getColor(s);
} catch (NumberFormatException e) {
mContext.getLogger().warning(String.format(
"Unable to convert \"%s\" into a color in attribute \"%2$s\"",
s, mNames[index]));
// we'll return the default value below.
ColorStateList colorStateList = ResourceHelper.getColorStateList(
mResourceData[index], mContext);
if (colorStateList != null) {
return colorStateList.getDefaultColor();
}
return defValue;
@@ -287,50 +294,57 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public ColorStateList getColorStateList(int index) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return null;
}
String value = mData[index].getValue();
ResourceValue resValue = mResourceData[index];
String value = resValue.getValue();
if (value == null) {
return null;
}
if (RenderResources.REFERENCE_NULL.equals(value)) {
return null;
}
// let the framework inflate the ColorStateList from the XML file.
File f = new File(value);
if (f.isFile()) {
try {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(f));
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
parser, mContext, resValue.isFramework());
try {
return ColorStateList.createFromXml(mContext.getResources(), blockParser);
} finally {
blockParser.ensurePopped();
}
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
"Failed to configure parser for " + value, e, null /*data*/);
return null;
} catch (Exception e) {
// this is an error and not warning since the file existence is checked before
// attempting to parse it.
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
"Failed to parse file " + value, e, null /*data*/);
return null;
}
}
try {
int color = ResourceHelper.getColor(value);
return ColorStateList.valueOf(color);
} catch (NumberFormatException e) {
// if it's not a color value, we'll attempt to read the xml based color below.
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null /*data*/);
}
// let the framework inflate the ColorStateList from the XML file.
try {
File f = new File(value);
if (f.isFile()) {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(f));
ColorStateList colorStateList = ColorStateList.createFromXml(
mContext.getResources(),
// FIXME: we need to know if this resource is platform or not
new BridgeXmlBlockParser(parser, mContext, false));
return colorStateList;
}
} catch (Exception e) {
// this is an error and not warning since the file existence is checked before
// attempting to parse it.
mContext.getLogger().error(e);
// return null below.
}
// looks like were unable to resolve the color value.
mContext.getLogger().warning(String.format(
"Unable to resolve color value \"%1$s\" in attribute \"%2$s\"",
value, mNames[index]));
return null;
}
@@ -345,19 +359,20 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getInteger(int index, int defValue) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return defValue;
}
String s = mData[index].getValue();
String s = mResourceData[index].getValue();
if (s != null) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
mContext.getLogger().warning(String.format(
"Unable to convert \"%s\" into a integer in attribute \"%2$s\"",
s, mNames[index]));
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format(
"\"%s\" in attribute \"%2$s\" cannont be converted to an integer.",
s, mNames[index]), null /*data*/);
// The default value is returned below.
}
@@ -384,11 +399,11 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public float getDimension(int index, float defValue) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return defValue;
}
String s = mData[index].getValue();
String s = mResourceData[index].getValue();
if (s == null) {
return defValue;
@@ -399,14 +414,19 @@ public final class BridgeTypedArray extends TypedArray {
return LayoutParams.WRAP_CONTENT;
}
if (RenderResources.REFERENCE_NULL.equals(s)) {
return defValue;
}
if (ResourceHelper.stringToFloat(s, mValue)) {
return mValue.getDimension(mResources.mMetrics);
return mValue.getDimension(mBridgeResources.mMetrics);
}
// looks like we were unable to resolve the dimension value
mContext.getLogger().warning(String.format(
"Unable to resolve dimension value \"%1$s\" in attribute \"%2$s\"",
s, mNames[index]));
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format(
"\"%1$s\" in attribute \"%2$s\" is not a valid format.",
s, mNames[index]), null /*data*/);
return defValue;
}
@@ -453,11 +473,11 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getDimensionPixelSize(int index, int defValue) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return defValue;
}
String s = mData[index].getValue();
String s = mResourceData[index].getValue();
if (s == null) {
return defValue;
@@ -468,6 +488,10 @@ public final class BridgeTypedArray extends TypedArray {
return LayoutParams.WRAP_CONTENT;
}
if (RenderResources.REFERENCE_NULL.equals(s)) {
return defValue;
}
// FIXME huh?
float f = getDimension(index, defValue);
@@ -476,8 +500,11 @@ public final class BridgeTypedArray extends TypedArray {
if (f == 0) return 0;
if (f > 0) return 1;
throw new UnsupportedOperationException("Can't convert to dimension: " +
Integer.toString(index));
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
"Can't convert to dimension: " + Integer.toString(index),
null, null /*data*/);
return defValue;
}
/**
@@ -519,11 +546,11 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public float getFraction(int index, int base, int pbase, float defValue) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return defValue;
}
String value = mData[index].getValue();
String value = mResourceData[index].getValue();
if (value == null) {
return defValue;
}
@@ -533,9 +560,10 @@ public final class BridgeTypedArray extends TypedArray {
}
// looks like we were unable to resolve the fraction value
mContext.getLogger().warning(String.format(
"Unable to resolve fraction value \"%1$s\" in attribute \"%2$s\"",
value, mNames[index]));
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format(
"\"%1$s\" in attribute \"%2$s\" cannont be converted to a fraction.",
value, mNames[index]), null /*data*/);
return defValue;
}
@@ -556,8 +584,8 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getResourceId(int index, int defValue) {
// get the IResource for this index
IResourceValue resValue = mData[index];
// get the Resource for this index
ResourceValue resValue = mResourceData[index];
// no data, return the default value.
if (resValue == null) {
@@ -565,24 +593,30 @@ public final class BridgeTypedArray extends TypedArray {
}
// check if this is a style resource
if (resValue instanceof IStyleResourceValue) {
if (resValue instanceof StyleResourceValue) {
// get the id that will represent this style.
return mContext.getDynamicIdByStyle((IStyleResourceValue)resValue);
return mContext.getDynamicIdByStyle((StyleResourceValue)resValue);
}
// if the attribute was a reference to an id, and not a declaration of an id (@+id), then
// the xml attribute value was "resolved" which leads us to a IResourceValue with
// getType() returning "id" and getName() returning the id name
if (RenderResources.REFERENCE_NULL.equals(resValue.getValue())) {
return defValue;
}
// if the attribute was a reference to a resource, and not a declaration of an id (@+id),
// then the xml attribute value was "resolved" which leads us to a ResourceValue with a
// valid getType() and getName() returning a resource name.
// (and getValue() returning null!). We need to handle this!
if (resValue.getType() != null && resValue.getType().equals(BridgeConstants.RES_ID)) {
if (resValue.getResourceType() != null) {
// if this is a framework id
if (mPlatformFile || resValue.isFramework()) {
// look for idName in the android R classes
return mContext.getFrameworkIdValue(resValue.getName(), defValue);
return mContext.getFrameworkResourceValue(
resValue.getResourceType(), resValue.getName(), defValue);
}
// look for idName in the project R class.
return mContext.getProjectIdValue(resValue.getName(), defValue);
return mContext.getProjectResourceValue(
resValue.getResourceType(), resValue.getName(), defValue);
}
// else, try to get the value, and resolve it somehow.
@@ -619,29 +653,33 @@ public final class BridgeTypedArray extends TypedArray {
// if this is a framework id
if (mPlatformFile || value.startsWith("@android") || value.startsWith("@+android")) {
// look for idName in the android R classes
return mContext.getFrameworkIdValue(idName, defValue);
return mContext.getFrameworkResourceValue(ResourceType.ID, idName, defValue);
}
// look for idName in the project R class.
return mContext.getProjectIdValue(idName, defValue);
return mContext.getProjectResourceValue(ResourceType.ID, idName, defValue);
}
// not a direct id valid reference? resolve it
Integer idValue = null;
if (resValue.isFramework()) {
idValue = Bridge.getResourceValue(resValue.getType(), resValue.getName());
idValue = Bridge.getResourceId(resValue.getResourceType(),
resValue.getName());
} else {
idValue = mContext.getProjectCallback().getResourceValue(
resValue.getType(), resValue.getName());
idValue = mContext.getProjectCallback().getResourceId(
resValue.getResourceType(), resValue.getName());
}
if (idValue != null) {
return idValue.intValue();
}
mContext.getLogger().warning(String.format(
"Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index]));
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
String.format(
"Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index]),
resValue);
return defValue;
}
@@ -657,28 +695,17 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public Drawable getDrawable(int index) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return null;
}
IResourceValue value = mData[index];
ResourceValue value = mResourceData[index];
String stringValue = value.getValue();
if (stringValue == null || BridgeConstants.REFERENCE_NULL.equals(stringValue)) {
if (stringValue == null || RenderResources.REFERENCE_NULL.equals(stringValue)) {
return null;
}
Drawable d = ResourceHelper.getDrawable(value, mContext, mData[index].isFramework());
if (d != null) {
return d;
}
// looks like we were unable to resolve the drawable
mContext.getLogger().warning(String.format(
"Unable to resolve drawable \"%1$s\" in attribute \"%2$s\"", stringValue,
mNames[index]));
return null;
return ResourceHelper.getDrawable(value, mContext);
}
@@ -694,18 +721,23 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public CharSequence[] getTextArray(int index) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return null;
}
String value = mData[index].getValue();
String value = mResourceData[index].getValue();
if (value != null) {
if (RenderResources.REFERENCE_NULL.equals(value)) {
return null;
}
return new CharSequence[] { value };
}
mContext.getLogger().warning(String.format(
String.format("Unknown value for getTextArray(%d) => %s", //DEBUG
index, mData[index].getName())));
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format(
String.format("Unknown value for getTextArray(%d) => %s", //DEBUG
index, mResourceData[index].getName())), null /*data*/);
return null;
}
@@ -721,11 +753,11 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public boolean getValue(int index, TypedValue outValue) {
if (mData[index] == null) {
if (mResourceData[index] == null) {
return false;
}
String s = mData[index].getValue();
String s = mResourceData[index].getValue();
return ResourceHelper.stringToFloat(s, outValue);
}
@@ -739,7 +771,7 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public boolean hasValue(int index) {
return mData[index] != null;
return mResourceData[index] != null;
}
/**
@@ -786,6 +818,6 @@ public final class BridgeTypedArray extends TypedArray {
@Override
public String toString() {
return mData.toString();
return Arrays.toString(mResourceData);
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2010 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.layoutlib.bridge.android;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.view.DragEvent;
import android.view.IWindow;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View.AttachInfo;
/**
* Implementation of {@link IWindow} to pass to the {@link AttachInfo}.
*/
public final class BridgeWindow implements IWindow {
public void dispatchAppVisibility(boolean arg0) throws RemoteException {
// pass for now.
}
public void dispatchGetNewSurface() throws RemoteException {
// pass for now.
}
public void dispatchKey(KeyEvent arg0) throws RemoteException {
// pass for now.
}
public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
// pass for now.
}
public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2)
throws RemoteException {
// pass for now.
}
public void executeCommand(String arg0, String arg1, ParcelFileDescriptor arg2)
throws RemoteException {
// pass for now.
}
public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5)
throws RemoteException {
// pass for now.
}
public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
// pass for now.
}
public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
boolean sync) {
// pass for now.
}
public void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
// pass for now.
}
public void closeSystemDialogs(String reason) {
// pass for now.
}
public void dispatchDragEvent(DragEvent event) {
// pass for now.
}
public void dispatchSystemUiVisibilityChanged(int visibility) {
// pass for now.
}
public IBinder asBinder() {
// pass for now.
return null;
}
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (C) 2010 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.layoutlib.bridge.android;
import android.content.ClipData;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.IWindow;
import android.view.IWindowSession;
import android.view.InputChannel;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.WindowManager.LayoutParams;
/**
* Implementation of {@link IWindowSession} so that mSession is not null in
* the {@link SurfaceView}.
*/
public final class BridgeWindowSession implements IWindowSession {
public int add(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3,
InputChannel outInputchannel)
throws RemoteException {
// pass for now.
return 0;
}
public int addWithoutInputChannel(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3)
throws RemoteException {
// pass for now.
return 0;
}
public void finishDrawing(IWindow arg0) throws RemoteException {
// pass for now.
}
public void finishKey(IWindow arg0) throws RemoteException {
// pass for now.
}
public boolean getInTouchMode() throws RemoteException {
// pass for now.
return false;
}
public boolean performHapticFeedback(IWindow window, int effectId, boolean always) {
// pass for now.
return false;
}
public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
// pass for now.
return null;
}
public MotionEvent getPendingTrackballMove(IWindow arg0) throws RemoteException {
// pass for now.
return null;
}
public int relayout(IWindow arg0, LayoutParams arg1, int arg2, int arg3, int arg4,
boolean arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
throws RemoteException {
// pass for now.
return 0;
}
public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
// pass for now.
}
public void remove(IWindow arg0) throws RemoteException {
// pass for now.
}
public void setInTouchMode(boolean arg0) throws RemoteException {
// pass for now.
}
public void setTransparentRegion(IWindow arg0, Region arg1) throws RemoteException {
// pass for now.
}
public void setInsets(IWindow window, int touchable, Rect contentInsets,
Rect visibleInsets, Region touchableRegion) {
// pass for now.
}
public IBinder prepareDrag(IWindow window, int flags,
int thumbnailWidth, int thumbnailHeight, Surface outSurface)
throws RemoteException {
// pass for now
return null;
}
public boolean performDrag(IWindow window, IBinder dragToken,
float touchX, float touchY, float thumbCenterX, float thumbCenterY,
ClipData data)
throws RemoteException {
// pass for now
return false;
}
public void reportDropResult(IWindow window, boolean consumed) throws RemoteException {
// pass for now
}
public void dragRecipientEntered(IWindow window) throws RemoteException {
// pass for now
}
public void dragRecipientExited(IWindow window) throws RemoteException {
// pass for now
}
public void setWallpaperPosition(IBinder window, float x, float y,
float xStep, float yStep) {
// pass for now.
}
public void wallpaperOffsetsComplete(IBinder window) {
// pass for now.
}
public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, Bundle extras, boolean sync) {
// pass for now.
return null;
}
public void wallpaperCommandComplete(IBinder window, Bundle result) {
// pass for now.
}
public void closeSystemDialogs(String reason) {
// pass for now.
}
public IBinder asBinder() {
// pass for now.
return null;
}
public IBinder prepareDrag(IWindow arg0, boolean arg1, int arg2, int arg3, Surface arg4)
throws RemoteException {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -14,9 +14,10 @@
* limitations under the License.
*/
package com.android.layoutlib.bridge;
package com.android.layoutlib.bridge.android;
import com.android.layoutlib.api.IXmlPullParser;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -36,14 +37,15 @@ import java.io.Reader;
*/
public class BridgeXmlBlockParser implements XmlResourceParser {
private XmlPullParser mParser;
private XmlPullAttributes mAttrib;
private final XmlPullParser mParser;
private final XmlPullAttributes mAttrib;
private final BridgeContext mContext;
private final boolean mPlatformFile;
private boolean mStarted = false;
private boolean mDecNextDepth = false;
private int mDepth = 0;
private int mEventType = START_DOCUMENT;
private final boolean mPlatformFile;
private boolean mPopped = true; // default to true in case it's not pushed.
/**
* Builds a {@link BridgeXmlBlockParser}.
@@ -53,25 +55,45 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
*/
public BridgeXmlBlockParser(XmlPullParser parser, BridgeContext context, boolean platformFile) {
mParser = parser;
mContext = context;
mPlatformFile = platformFile;
mAttrib = new BridgeXmlPullAttributes(parser, context, mPlatformFile);
if (mContext != null) {
mContext.pushParser(this);
mPopped = false;
}
}
public boolean isPlatformFile() {
return mPlatformFile;
}
public Object getViewKey() {
if (mParser instanceof IXmlPullParser) {
return ((IXmlPullParser)mParser).getViewKey();
public ILayoutPullParser getParser(String layoutName) {
if (mParser instanceof ILayoutPullParser) {
return ((ILayoutPullParser)mParser).getParser(layoutName);
}
return null;
}
public Object getViewCookie() {
if (mParser instanceof ILayoutPullParser) {
return ((ILayoutPullParser)mParser).getViewCookie();
}
return null;
}
public void ensurePopped() {
if (mContext != null && mPopped == false) {
mContext.popParser();
mPopped = true;
}
}
// ------- XmlResourceParser implementation
public void setFeature(String name, boolean state)
throws XmlPullParserException {
if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) {
@@ -145,7 +167,7 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
}
public int getDepth() {
return mDepth;
return mParser.getDepth();
}
public String getText() {
@@ -236,17 +258,10 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
return START_DOCUMENT;
}
int ev = mParser.next();
if (mDecNextDepth) {
mDepth--;
mDecNextDepth = false;
}
switch (ev) {
case START_TAG:
mDepth++;
break;
case END_TAG:
mDecNextDepth = true;
break;
if (ev == END_TAG && mParser.getDepth() == 1) {
// done with parser remove it from the context stack.
ensurePopped();
}
mEventType = ev;
return ev;
@@ -301,7 +316,7 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
// AttributeSet implementation
public void close() {
// pass
}

View File

@@ -14,9 +14,13 @@
* limitations under the License.
*/
package com.android.layoutlib.bridge;
package com.android.layoutlib.bridge.android;
import com.android.layoutlib.api.IResourceValue;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.resources.ResourceType;
import org.xmlpull.v1.XmlPullParser;
@@ -55,7 +59,7 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
String ns = mParser.getAttributeNamespace(index);
if (BridgeConstants.NS_RESOURCES.equals(ns)) {
Integer v = Bridge.getResourceValue(BridgeConstants.RES_ATTR, name);
Integer v = Bridge.getResourceId(ResourceType.ATTR, name);
if (v != null) {
return v.intValue();
}
@@ -66,8 +70,7 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
// this is not an attribute in the android namespace, we query the customviewloader, if
// the namespaces match.
if (mContext.getProjectCallback().getNamespace().equals(ns)) {
Integer v = mContext.getProjectCallback().getResourceValue(BridgeConstants.RES_ATTR,
name);
Integer v = mContext.getProjectCallback().getResourceId(ResourceType.ATTR, name);
if (v != null) {
return v.intValue();
}
@@ -100,16 +103,17 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
private int resolveResourceValue(String value, int defaultValue) {
// now look for this particular value
IResourceValue resource = mContext.resolveResValue(
mContext.findResValue(value, mPlatformFile));
RenderResources resources = mContext.getRenderResources();
ResourceValue resource = resources.resolveResValue(
resources.findResValue(value, mPlatformFile));
if (resource != null) {
Integer id = null;
if (mPlatformFile || resource.isFramework()) {
id = Bridge.getResourceValue(resource.getType(), resource.getName());
id = Bridge.getResourceId(resource.getResourceType(), resource.getName());
} else {
id = mContext.getProjectCallback().getResourceValue(
resource.getType(), resource.getName());
id = mContext.getProjectCallback().getResourceId(
resource.getResourceType(), resource.getName());
}
if (id != null) {

View File

@@ -0,0 +1,263 @@
/*
* 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.layoutlib.bridge.bars;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.StyleResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.resources.Density;
import com.android.resources.ResourceType;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
/**
* Base "bar" class for the window decor around the the edited layout.
* This is basically an horizontal layout that loads a given layout on creation (it is read
* through {@link Class#getResourceAsStream(String)}).
*
* The given layout should be a merge layout so that all the children belong to this class directly.
*
* It also provides a few utility methods to configure the content of the layout.
*/
abstract class CustomBar extends LinearLayout {
protected abstract TextView getStyleableTextView();
protected CustomBar(Context context, Density density, String layoutPath)
throws XmlPullParserException {
super(context);
setOrientation(LinearLayout.HORIZONTAL);
setGravity(Gravity.CENTER_VERTICAL);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(
getClass().getResourceAsStream(layoutPath),
"UTF8");
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
parser, (BridgeContext) context, false /*platformFile*/);
try {
inflater.inflate(bridgeParser, this, true);
} finally {
bridgeParser.ensurePopped();
}
}
private InputStream getIcon(String iconName, Density[] densityInOut, String[] pathOut,
boolean tryOtherDensities) {
// current density
Density density = densityInOut[0];
// bitmap url relative to this class
pathOut[0] = "/bars/" + density.getResourceValue() + "/" + iconName;
InputStream stream = getClass().getResourceAsStream(pathOut[0]);
if (stream == null && tryOtherDensities) {
for (Density d : Density.values()) {
if (d != density) {
densityInOut[0] = d;
stream = getIcon(iconName, densityInOut, pathOut, false /*tryOtherDensities*/);
if (stream != null) {
return stream;
}
}
}
}
return stream;
}
protected void loadIcon(int index, String iconName, Density density) {
View child = getChildAt(index);
if (child instanceof ImageView) {
ImageView imageView = (ImageView) child;
String[] pathOut = new String[1];
Density[] densityInOut = new Density[] { density };
InputStream stream = getIcon(iconName, densityInOut, pathOut,
true /*tryOtherDensities*/);
density = densityInOut[0];
if (stream != null) {
// look for a cached bitmap
Bitmap bitmap = Bridge.getCachedBitmap(pathOut[0], true /*isFramework*/);
if (bitmap == null) {
try {
bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
Bridge.setCachedBitmap(pathOut[0], bitmap, true /*isFramework*/);
} catch (IOException e) {
return;
}
}
if (bitmap != null) {
BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(),
bitmap);
imageView.setBackgroundDrawable(drawable);
}
}
}
}
protected void loadIcon(int index, String iconReference) {
ResourceValue value = getResourceValue(iconReference);
if (value != null) {
loadIcon(index, value);
}
}
protected Drawable loadIcon(int index, ResourceType type, String name) {
BridgeContext bridgeContext = (BridgeContext) mContext;
RenderResources res = bridgeContext.getRenderResources();
// find the resource
ResourceValue value = res.getFrameworkResource(type, name);
// resolve it if needed
value = res.resolveResValue(value);
return loadIcon(index, value);
}
private Drawable loadIcon(int index, ResourceValue value) {
View child = getChildAt(index);
if (child instanceof ImageView) {
ImageView imageView = (ImageView) child;
Drawable drawable = ResourceHelper.getDrawable(
value, (BridgeContext) mContext);
if (drawable != null) {
imageView.setBackgroundDrawable(drawable);
}
return drawable;
}
return null;
}
protected TextView setText(int index, String stringReference) {
View child = getChildAt(index);
if (child instanceof TextView) {
TextView textView = (TextView) child;
ResourceValue value = getResourceValue(stringReference);
if (value != null) {
textView.setText(value.getValue());
} else {
textView.setText(stringReference);
}
return textView;
}
return null;
}
protected void setStyle(String themeEntryName) {
BridgeContext bridgeContext = (BridgeContext) mContext;
RenderResources res = bridgeContext.getRenderResources();
ResourceValue value = res.findItemInTheme(themeEntryName);
value = res.resolveResValue(value);
if (value instanceof StyleResourceValue == false) {
return;
}
StyleResourceValue style = (StyleResourceValue) value;
// get the background
ResourceValue backgroundValue = res.findItemInStyle(style, "background");
backgroundValue = res.resolveResValue(backgroundValue);
if (backgroundValue != null) {
Drawable d = ResourceHelper.getDrawable(backgroundValue, bridgeContext);
if (d != null) {
setBackgroundDrawable(d);
}
}
TextView textView = getStyleableTextView();
if (textView != null) {
// get the text style
ResourceValue textStyleValue = res.findItemInStyle(style, "titleTextStyle");
textStyleValue = res.resolveResValue(textStyleValue);
if (textStyleValue instanceof StyleResourceValue) {
StyleResourceValue textStyle = (StyleResourceValue) textStyleValue;
ResourceValue textSize = res.findItemInStyle(textStyle, "textSize");
textSize = res.resolveResValue(textSize);
if (textSize != null) {
TypedValue out = new TypedValue();
if (ResourceHelper.stringToFloat(textSize.getValue(), out)) {
textView.setTextSize(
out.getDimension(bridgeContext.getResources().mMetrics));
}
}
ResourceValue textColor = res.findItemInStyle(textStyle, "textColor");
textColor = res.resolveResValue(textColor);
if (textColor != null) {
ColorStateList stateList = ResourceHelper.getColorStateList(
textColor, bridgeContext);
if (stateList != null) {
textView.setTextColor(stateList);
}
}
}
}
}
private ResourceValue getResourceValue(String reference) {
BridgeContext bridgeContext = (BridgeContext) mContext;
RenderResources res = bridgeContext.getRenderResources();
// find the resource
ResourceValue value = res.findResValue(reference, false /*isFramework*/);
// resolve it if needed
return res.resolveResValue(value);
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.layoutlib.bridge.bars;
import com.android.resources.Density;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.widget.TextView;
public class FakeActionBar extends CustomBar {
private TextView mTextView;
public FakeActionBar(Context context, Density density, String label, String icon)
throws XmlPullParserException {
super(context, density, "/bars/action_bar.xml");
// Cannot access the inside items through id because no R.id values have been
// created for them.
// We do know the order though.
loadIcon(0, icon);
mTextView = setText(1, label);
setStyle("actionBarStyle");
}
@Override
protected TextView getStyleableTextView() {
return mTextView;
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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.layoutlib.bridge.bars;
import com.android.resources.Density;
import com.android.resources.ResourceType;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LevelListDrawable;
import android.view.Gravity;
import android.widget.TextView;
public class PhoneSystemBar extends CustomBar {
public PhoneSystemBar(Context context, Density density) throws XmlPullParserException {
super(context, density, "/bars/phone_system_bar.xml");
setGravity(mGravity | Gravity.RIGHT);
setBackgroundColor(0xFF000000);
// Cannot access the inside items through id because no R.id values have been
// created for them.
// We do know the order though.
// 0 is the spacer
loadIcon(1, "stat_sys_wifi_signal_4_fully.png", density);
Drawable drawable = loadIcon(2, ResourceType.DRAWABLE, "stat_sys_battery_charge");
if (drawable instanceof LevelListDrawable) {
((LevelListDrawable) drawable).setLevel(100);
}
}
@Override
protected TextView getStyleableTextView() {
return null;
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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.layoutlib.bridge.bars;
import com.android.resources.Density;
import com.android.resources.ResourceType;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LevelListDrawable;
import android.widget.TextView;
public class TabletSystemBar extends CustomBar {
public TabletSystemBar(Context context, Density density) throws XmlPullParserException {
super(context, density, "/bars/tablet_system_bar.xml");
setBackgroundColor(0xFF000000);
// Cannot access the inside items through id because no R.id values have been
// created for them.
// We do know the order though.
loadIcon(0, "ic_sysbar_back_default.png", density);
loadIcon(1, "ic_sysbar_home_default.png", density);
loadIcon(2, "ic_sysbar_recent_default.png", density);
// 3 is the spacer
loadIcon(4, "stat_sys_wifi_signal_4_fully.png", density);
Drawable drawable = loadIcon(5, ResourceType.DRAWABLE, "stat_sys_battery_charge");
if (drawable instanceof LevelListDrawable) {
((LevelListDrawable) drawable).setLevel(100);
}
}
@Override
protected TextView getStyleableTextView() {
return null;
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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.layoutlib.bridge.bars;
import com.android.resources.Density;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.widget.TextView;
public class TitleBar extends CustomBar {
private TextView mTextView;
public TitleBar(Context context, Density density, String label)
throws XmlPullParserException {
super(context, density, "/bars/title_bar.xml");
// Cannot access the inside items through id because no R.id values have been
// created for them.
// We do know the order though.
mTextView = setText(0, label);
setStyle("windowTitleBackgroundStyle");
}
@Override
protected TextView getStyleableTextView() {
return mTextView;
}
}

Some files were not shown because too many files have changed in this diff Show More