LayoutLib: Original import of Honeycomb's layoutlib. do not merge.
frameworks/base.git @ f0a53435f1
Change-Id: Ibc215751693dc7650683b61bb458f7c8beaf8060
4
tools/layoutlib/README
Normal 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.
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
9
tools/layoutlib/bridge/resources/bars/action_bar.xml
Normal 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>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 885 B |
|
After Width: | Height: | Size: 204 B |
15
tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
Normal 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>
|
||||
24
tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml
Normal 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>
|
||||
6
tools/layoutlib/bridge/resources/bars/title_bar.xml
Normal 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>
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
104
tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
563
tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
1334
tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
Normal 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 ----
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ----
|
||||
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
1129
tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
Normal 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*/);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
1240
tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
Normal 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 */);
|
||||
}
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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 ----
|
||||
|
||||
}
|
||||
761
tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
484
tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
Normal 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 ----
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
105
tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 ----
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
};*/
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 ----
|
||||
|
||||
}
|
||||
48
tools/layoutlib/bridge/src/android/os/Build_Delegate.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
57
tools/layoutlib/bridge/src/android/os/Handler_Delegate.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//----------
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||