diff options
51 files changed, 1556 insertions, 917 deletions
diff --git a/api/11.xml b/api/11.xml index 173365267912..1ac57a16d1fc 100644 --- a/api/11.xml +++ b/api/11.xml @@ -4250,6 +4250,17 @@ visibility="public" > </field> +<field name="fastScrollTextColor" + type="int" + transient="false" + volatile="false" + value="16843611" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="fastScrollThumbDrawable" type="int" transient="false" @@ -5812,6 +5823,17 @@ visibility="public" > </field> +<field name="largeHeap" + type="int" + transient="false" + volatile="false" + value="16843612" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="largeScreens" type="int" transient="false" @@ -11462,6 +11484,28 @@ visibility="public" > </field> +<field name="notification_large_icon_height" + type="int" + transient="false" + volatile="false" + value="17104902" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="notification_large_icon_width" + type="int" + transient="false" + volatile="false" + value="17104901" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="thumbnail_height" type="int" transient="false" @@ -25114,17 +25158,6 @@ visibility="public" > </field> -<field name="TASKS_GET_THUMBNAILS" - type="int" - transient="false" - volatile="false" - value="4096" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> </class> <class name="ActivityManager.MemoryInfo" extends="java.lang.Object" @@ -25523,16 +25556,6 @@ visibility="public" > </field> -<field name="thumbnail" - type="android.graphics.Bitmap" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> </class> <class name="ActivityManager.RunningAppProcessInfo" extends="java.lang.Object" @@ -38947,6 +38970,17 @@ visibility="public" > </method> +<method name="clearViews" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="protected" +> +</method> <method name="createView" return="android.appwidget.AppWidgetHostView" abstract="false" @@ -48119,6 +48153,17 @@ visibility="public" > </method> +<method name="getObbDir" + return="java.io.File" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getPackageCodePath" return="java.lang.String" abstract="true" @@ -49727,6 +49772,17 @@ visibility="public" > </method> +<method name="getObbDir" + return="java.io.File" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getPackageCodePath" return="java.lang.String" abstract="false" @@ -58210,6 +58266,17 @@ visibility="public" > </field> +<field name="FLAG_LARGE_HEAP" + type="int" + transient="false" + volatile="false" + value="1048576" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="FLAG_PERSISTENT" type="int" transient="false" @@ -60220,6 +60287,19 @@ <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException"> </exception> </method> +<method name="getPackageObbPaths" + return="java.lang.String[]" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="packageName" type="java.lang.String"> +</parameter> +</method> <method name="getPackagesForUid" return="java.lang.String[]" abstract="true" @@ -60706,6 +60786,21 @@ <parameter name="installerPackageName" type="java.lang.String"> </parameter> </method> +<method name="setPackageObbPaths" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="packageName" type="java.lang.String"> +</parameter> +<parameter name="paths" type="java.lang.String[]"> +</parameter> +</method> <field name="COMPONENT_ENABLED_STATE_DEFAULT" type="int" transient="false" @@ -137446,6 +137541,34 @@ <parameter name="params" type="Params..."> </parameter> </method> +<method name="execute" + return="void" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="runnable" type="java.lang.Runnable"> +</parameter> +</method> +<method name="executeOnExecutor" + return="android.os.AsyncTask<Params, Progress, Result>" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="exec" type="java.util.concurrent.Executor"> +</parameter> +<parameter name="params" type="Params..."> +</parameter> +</method> <method name="get" return="Result" abstract="false" @@ -137578,6 +137701,16 @@ <parameter name="values" type="Progress..."> </parameter> </method> +<field name="THREAD_POOL_EXECUTOR" + type="java.util.concurrent.ThreadPoolExecutor" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> <class name="AsyncTask.Status" extends="java.lang.Enum" @@ -185171,6 +185304,19 @@ <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException"> </exception> </method> +<method name="getPackageObbPaths" + return="java.lang.String[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="packageName" type="java.lang.String"> +</parameter> +</method> <method name="getPackagesForUid" return="java.lang.String[]" abstract="false" @@ -185670,6 +185816,21 @@ <parameter name="path" type="java.lang.String"> </parameter> </method> +<method name="setPackageObbPaths" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="packageName" type="java.lang.String"> +</parameter> +<parameter name="paths" type="java.lang.String[]"> +</parameter> +</method> </class> <class name="MockResources" extends="android.content.res.Resources" @@ -238084,6 +238245,34 @@ > </field> </class> +<class name="WebViewFragment" + extends="android.app.Fragment" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="WebViewFragment" + type="android.webkit.WebViewFragment" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<method name="getWebView" + return="android.webkit.WebView" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +</class> </package> <package name="android.widget" > diff --git a/api/current.xml b/api/current.xml index f7172f40bc5d..6b7907472981 100644 --- a/api/current.xml +++ b/api/current.xml @@ -25158,17 +25158,6 @@ visibility="public" > </field> -<field name="TASKS_GET_THUMBNAILS" - type="int" - transient="false" - volatile="false" - value="4096" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> </class> <class name="ActivityManager.MemoryInfo" extends="java.lang.Object" @@ -25567,16 +25556,6 @@ visibility="public" > </field> -<field name="thumbnail" - type="android.graphics.Bitmap" - transient="false" - volatile="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</field> </class> <class name="ActivityManager.RunningAppProcessInfo" extends="java.lang.Object" @@ -48174,6 +48153,17 @@ visibility="public" > </method> +<method name="getObbDir" + return="java.io.File" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getPackageCodePath" return="java.lang.String" abstract="true" @@ -49782,6 +49772,17 @@ visibility="public" > </method> +<method name="getObbDir" + return="java.io.File" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getPackageCodePath" return="java.lang.String" abstract="false" @@ -95606,6 +95607,17 @@ visibility="public" > </field> +<field name="TOUCHABLE_INSETS_REGION" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="TOUCHABLE_INSETS_VISIBLE" type="int" transient="false" @@ -95637,6 +95649,16 @@ visibility="public" > </field> +<field name="touchableRegion" + type="android.graphics.Region" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="visibleTopInsets" type="int" transient="false" diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 4eae14bce98c..d5aa9619962c 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -122,6 +122,8 @@ public class ActivityManager { /** * Thumbnail representation of the task's last state. Must * use {@link ActivityManager#TASKS_GET_THUMBNAILS} to have this set. + * @hide -- this is not scalable, need to have a separate API to get + * the bitmap. */ public Bitmap thumbnail; @@ -203,6 +205,7 @@ public class ActivityManager { /** * Flag for use with {@link #getRecentTasks}: also return the thumbnail * bitmap (if available) for each recent task. + * @hide */ public static final int TASKS_GET_THUMBNAILS = 0x0001000; @@ -214,8 +217,7 @@ public class ActivityManager { * actual number returned may be smaller, depending on how many tasks the * user has started and the maximum number the system can remember. * @param flags Information about what to return. May be any combination - * of {@link #RECENT_WITH_EXCLUDED}, {@link #RECENT_IGNORE_UNAVAILABLE}, - * and {@link #TASKS_GET_THUMBNAILS}. + * of {@link #RECENT_WITH_EXCLUDED} and {@link #RECENT_IGNORE_UNAVAILABLE}. * * @return Returns a list of RecentTaskInfo records describing each of * the recent tasks. @@ -261,8 +263,8 @@ public class ActivityManager { public ComponentName topActivity; /** - * Thumbnail representation of the task's current state. Must - * use {@link ActivityManager#TASKS_GET_THUMBNAILS} to have this set. + * Thumbnail representation of the task's current state. Currently + * always null. */ public Bitmap thumbnail; diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index e133ea02e29f..6f639906097d 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -153,6 +153,7 @@ class ContextImpl extends Context { private File mPreferencesDir; private File mFilesDir; private File mCacheDir; + private File mObbDir; private File mExternalFilesDir; private File mExternalCacheDir; @@ -647,6 +648,17 @@ class ContextImpl extends Context { } @Override + public File getObbDir() { + synchronized (mSync) { + if (mObbDir == null) { + mObbDir = Environment.getExternalStorageAppObbDirectory( + getPackageName()); + } + return mObbDir; + } + } + + @Override public File getCacheDir() { synchronized (mSync) { if (mCacheDir == null) { diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java index a5c49ecb5caf..35cc3248f456 100644 --- a/core/java/android/app/NativeActivity.java +++ b/core/java/android/app/NativeActivity.java @@ -84,7 +84,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, private boolean mDestroyed; private native int loadNativeCode(String path, String funcname, MessageQueue queue, - String internalDataPath, String externalDataPath, int sdkVersion, + String internalDataPath, String obbPath, String externalDataPath, int sdkVersion, AssetManager assetMgr, byte[] savedState); private native void unloadNativeCode(int handle); @@ -191,7 +191,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null; mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(), - getFilesDir().toString(), + getFilesDir().toString(), getObbDir().toString(), Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(), Build.VERSION.SDK_INT, getAssets(), nativeSavedState); diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 4f8ee9382d76..d8adc6cc1cc0 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -94,8 +94,12 @@ public class AppWidgetHostView extends FrameLayout { public AppWidgetHostView(Context context, int animationIn, int animationOut) { super(context); mContext = context; + + // We want to segregate the view ids within AppWidgets to prevent + // problems when those ids collide with view ids in the AppWidgetHost. + setIsRootNamespace(true); } - + /** * Set the AppWidget that will be displayed by this view. */ diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 227df21d2462..d14cf4d56fc1 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -516,6 +516,13 @@ public abstract class Context { public abstract File getExternalFilesDir(String type); /** + * Return the directory where this application's OBB files (if there + * are any) can be found. Note if the application does not have any OBB + * files, this directory may not exist. + */ + public abstract File getObbDir(); + + /** * Returns the absolute path to the application specific cache directory * on the filesystem. These files will be ones that get deleted first when the * device runs low on storage. diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 545144ee1eee..3928aaf62d10 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -191,6 +191,11 @@ public class ContextWrapper extends Context { } @Override + public File getObbDir() { + return mBase.getObbDir(); + } + + @Override public File getCacheDir() { return mBase.getCacheDir(); } diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index 406b091278f8..6baf1c21db88 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -283,6 +283,7 @@ public class CompatibilityInfo { private Rect mContentInsetsBuffer = null; private Rect mVisibleInsetsBuffer = null; + private Region mTouchableAreaBuffer = null; Translator(float applicationScale, float applicationInvertedScale) { this.applicationScale = applicationScale; @@ -395,14 +396,25 @@ public class CompatibilityInfo { /** * Translate the visible insets in application window to Screen. This uses - * the internal buffer for content insets to avoid extra object allocation. + * the internal buffer for visible insets to avoid extra object allocation. */ - public Rect getTranslatedVisbileInsets(Rect visibleInsets) { + public Rect getTranslatedVisibleInsets(Rect visibleInsets) { if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect(); mVisibleInsetsBuffer.set(visibleInsets); translateRectInAppWindowToScreen(mVisibleInsetsBuffer); return mVisibleInsetsBuffer; } + + /** + * Translate the touchable area in application window to Screen. This uses + * the internal buffer for touchable area to avoid extra object allocation. + */ + public Region getTranslatedTouchableArea(Region touchableArea) { + if (mTouchableAreaBuffer == null) mTouchableAreaBuffer = new Region(); + mTouchableAreaBuffer.set(touchableArea); + mTouchableAreaBuffer.scale(applicationScale); + return mTouchableAreaBuffer; + } } /** diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 23b9ad583edf..4d25bac067d4 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -25,6 +25,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Rect; +import android.graphics.Region; import android.os.Bundle; import android.os.IBinder; import android.os.ResultReceiver; @@ -283,11 +284,13 @@ public class InputMethodService extends AbstractInputMethodService { View decor = getWindow().getWindow().getDecorView(); info.contentInsets.top = info.visibleInsets.top = decor.getHeight(); + info.touchableRegion.setEmpty(); info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); } else { onComputeInsets(mTmpInsets); info.contentInsets.top = mTmpInsets.contentTopInsets; info.visibleInsets.top = mTmpInsets.visibleTopInsets; + info.touchableRegion.set(mTmpInsets.touchableRegion); info.setTouchableInsets(mTmpInsets.touchableInsets); } } @@ -510,7 +513,14 @@ public class InputMethodService extends AbstractInputMethodService { * of the input method window. */ public int visibleTopInsets; - + + /** + * This is the region of the UI that is touchable. It is used when + * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}. + * The region should be specified relative to the origin of the window frame. + */ + public final Region touchableRegion = new Region(); + /** * Option for {@link #touchableInsets}: the entire window frame * can be touched. @@ -531,11 +541,19 @@ public class InputMethodService extends AbstractInputMethodService { */ public static final int TOUCHABLE_INSETS_VISIBLE = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE; - + + /** + * Option for {@link #touchableInsets}: the region specified by + * {@link #touchableRegion} can be touched. + */ + public static final int TOUCHABLE_INSETS_REGION + = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; + /** * Determine which area of the window is touchable by the user. May * be one of: {@link #TOUCHABLE_INSETS_FRAME}, - * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_VISIBLE}. + * {@link #TOUCHABLE_INSETS_CONTENT}, {@link #TOUCHABLE_INSETS_VISIBLE}, + * or {@link #TOUCHABLE_INSETS_REGION}. */ public int touchableInsets; } @@ -950,6 +968,7 @@ public class InputMethodService extends AbstractInputMethodService { } outInsets.visibleTopInsets = loc[1]; outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE; + outInsets.touchableRegion.setEmpty(); } /** @@ -2153,6 +2172,7 @@ public class InputMethodService extends AbstractInputMethodService { p.println("Last computed insets:"); p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets + " visibleTopInsets=" + mTmpInsets.visibleTopInsets - + " touchableInsets=" + mTmpInsets.touchableInsets); + + " touchableInsets=" + mTmpInsets.touchableInsets + + " touchableRegion=" + mTmpInsets.touchableRegion); } } diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 4f188f8576d4..cc956428fb5a 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -107,6 +107,10 @@ public class Environment { = new File (new File(getDirectory("EXTERNAL_STORAGE", "/sdcard"), "Android"), "media"); + private static final File EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY + = new File (new File(getDirectory("EXTERNAL_STORAGE", "/sdcard"), + "Android"), "obb"); + private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache"); @@ -304,6 +308,14 @@ public class Environment { } /** + * Generates the raw path to an application's OBB files + * @hide + */ + public static File getExternalStorageAppObbDirectory(String packageName) { + return new File(EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY, packageName); + } + + /** * Generates the path to an application's files. * @hide */ diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index a5f405aca1e4..1218e81d7708 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -101,7 +101,7 @@ interface IWindowSession { * {@link android.view.ViewTreeObserver.InternalInsetsInfo}. */ void setInsets(IWindow window, int touchableInsets, in Rect contentInsets, - in Rect visibleInsets); + in Rect visibleInsets, in Region touchableRegion); /** * Return the current display size in which the window is being laid out, diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index e2285373c7e8..96f8cdcce70b 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -1229,24 +1229,34 @@ public final class ViewRoot extends Handler implements ViewParent, } if (computesInternalInsets) { - ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets; - final Rect givenContent = attachInfo.mGivenInternalInsets.contentInsets; - final Rect givenVisible = attachInfo.mGivenInternalInsets.visibleInsets; - givenContent.left = givenContent.top = givenContent.right - = givenContent.bottom = givenVisible.left = givenVisible.top - = givenVisible.right = givenVisible.bottom = 0; + // Clear the original insets. + final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets; + insets.reset(); + + // Compute new insets in place. attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets); - Rect contentInsets = insets.contentInsets; - Rect visibleInsets = insets.visibleInsets; - if (mTranslator != null) { - contentInsets = mTranslator.getTranslatedContentInsets(contentInsets); - visibleInsets = mTranslator.getTranslatedVisbileInsets(visibleInsets); - } + + // Tell the window manager. if (insetsPending || !mLastGivenInsets.equals(insets)) { mLastGivenInsets.set(insets); + + // Translate insets to screen coordinates if needed. + final Rect contentInsets; + final Rect visibleInsets; + final Region touchableRegion; + if (mTranslator != null) { + contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets); + visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets); + touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion); + } else { + contentInsets = insets.contentInsets; + visibleInsets = insets.visibleInsets; + touchableRegion = insets.touchableRegion; + } + try { sWindowSession.setInsets(mWindow, insets.mTouchableInsets, - contentInsets, visibleInsets); + contentInsets, visibleInsets, touchableRegion); } catch (RemoteException e) { } } diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java index 06a0fa6eb8ee..db8717517e48 100644 --- a/core/java/android/view/ViewTreeObserver.java +++ b/core/java/android/view/ViewTreeObserver.java @@ -17,6 +17,7 @@ package android.view; import android.graphics.Rect; +import android.graphics.Region; import java.util.ArrayList; import java.util.concurrent.CopyOnWriteArrayList; @@ -126,11 +127,18 @@ public final class ViewTreeObserver { public final Rect contentInsets = new Rect(); /** - * Offsets from the fram of the window at which windows behind it + * Offsets from the frame of the window at which windows behind it * are visible. */ public final Rect visibleInsets = new Rect(); - + + /** + * Touchable region defined relative to the origin of the frame of the window. + * Only used when {@link #setTouchableInsets(int)} is called with + * the option {@link #TOUCHABLE_INSETS_REGION}. + */ + public final Region touchableRegion = new Region(); + /** * Option for {@link #setTouchableInsets(int)}: the entire window frame * can be touched. @@ -148,11 +156,17 @@ public final class ViewTreeObserver { * the visible insets can be touched. */ public static final int TOUCHABLE_INSETS_VISIBLE = 2; - + + /** + * Option for {@link #setTouchableInsets(int)}: the area inside of + * the provided touchable region in {@link #touchableRegion} can be touched. + */ + public static final int TOUCHABLE_INSETS_REGION = 3; + /** * Set which parts of the window can be touched: either * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT}, - * or {@link #TOUCHABLE_INSETS_VISIBLE}. + * {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}. */ public void setTouchableInsets(int val) { mTouchableInsets = val; @@ -165,11 +179,9 @@ public final class ViewTreeObserver { int mTouchableInsets; void reset() { - final Rect givenContent = contentInsets; - final Rect givenVisible = visibleInsets; - givenContent.left = givenContent.top = givenContent.right - = givenContent.bottom = givenVisible.left = givenVisible.top - = givenVisible.right = givenVisible.bottom = 0; + contentInsets.setEmpty(); + visibleInsets.setEmpty(); + touchableRegion.setEmpty(); mTouchableInsets = TOUCHABLE_INSETS_FRAME; } @@ -179,13 +191,16 @@ public final class ViewTreeObserver { return false; } InternalInsetsInfo other = (InternalInsetsInfo)o; + if (mTouchableInsets != other.mTouchableInsets) { + return false; + } if (!contentInsets.equals(other.contentInsets)) { return false; } if (!visibleInsets.equals(other.visibleInsets)) { return false; } - return mTouchableInsets == other.mTouchableInsets; + return touchableRegion.equals(other.touchableRegion); } catch (ClassCastException e) { return false; } @@ -194,6 +209,7 @@ public final class ViewTreeObserver { void set(InternalInsetsInfo other) { contentInsets.set(other.contentInsets); visibleInsets.set(other.visibleInsets); + touchableRegion.set(other.touchableRegion); mTouchableInsets = other.mTouchableInsets; } } diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java index b38838d5642f..2c100773951c 100644 --- a/core/java/android/widget/StackView.java +++ b/core/java/android/widget/StackView.java @@ -208,15 +208,12 @@ public class StackView extends AdapterViewAnimator { } } - if (fromIndex == -1 && toIndex == NUM_ACTIVE_VIEWS -1) { + if (fromIndex == -1 && toIndex == getNumActiveViews() -1) { // Fade item in if (view.getAlpha() == 1) { view.setAlpha(0); } - view.setScaleX(1 - PERSPECTIVE_SCALE_FACTOR); - view.setScaleY(1 - PERSPECTIVE_SCALE_FACTOR); - view.setTranslationX(mPerspectiveShiftX); - view.setTranslationY(0); + transformViewAtIndex(toIndex, view, false); view.setVisibility(VISIBLE); alphaOa = ObjectAnimator.ofFloat(view, "alpha", view.getAlpha(), 1.0f); diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index d28bdc91213f..f023e9469578 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -63,7 +63,6 @@ extern int register_android_graphics_MaskFilter(JNIEnv* env); extern int register_android_graphics_Movie(JNIEnv* env); extern int register_android_graphics_NinePatch(JNIEnv*); extern int register_android_graphics_PathEffect(JNIEnv* env); -extern int register_android_graphics_Region(JNIEnv* env); extern int register_android_graphics_Shader(JNIEnv* env); extern int register_android_graphics_Typeface(JNIEnv* env); extern int register_android_graphics_YuvImage(JNIEnv* env); @@ -111,6 +110,7 @@ extern int register_android_graphics_PathMeasure(JNIEnv* env); extern int register_android_graphics_Picture(JNIEnv*); extern int register_android_graphics_PorterDuff(JNIEnv* env); extern int register_android_graphics_Rasterizer(JNIEnv* env); +extern int register_android_graphics_Region(JNIEnv* env); extern int register_android_graphics_SurfaceTexture(JNIEnv* env); extern int register_android_graphics_Xfermode(JNIEnv* env); extern int register_android_graphics_PixelFormat(JNIEnv* env); diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp index 723cd37b8877..c43b5ce14eb1 100644 --- a/core/jni/android/graphics/Region.cpp +++ b/core/jni/android/graphics/Region.cpp @@ -1,8 +1,30 @@ +/* + * 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. + */ + #include "SkRegion.h" #include "SkPath.h" #include "GraphicsJNI.h" +#include <binder/Parcel.h> +#include "android_util_Binder.h" + #include <jni.h> +#include <android_runtime/AndroidRuntime.h> + +namespace android { static jfieldID gRegion_nativeInstanceFieldID; @@ -134,9 +156,6 @@ static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst) //////////////////////////////////////////////////////////////////////////////////////////////////////////// -#include <binder/Parcel.h> -#include "android_util_Binder.h" - static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel) { if (parcel == NULL) { @@ -215,8 +234,6 @@ static jboolean RegionIter_next(JNIEnv* env, jobject, RgnIterPair* pair, jobject //////////////////////////////////////////////////////////////////////////////////////////////////////////// -#include <android_runtime/AndroidRuntime.h> - static JNINativeMethod gRegionIterMethods[] = { { "nativeConstructor", "(I)I", (void*)RegionIter_constructor }, { "nativeDestructor", "(I)V", (void*)RegionIter_destructor }, @@ -268,3 +285,9 @@ int register_android_graphics_Region(JNIEnv* env) return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/RegionIterator", gRegionIterMethods, SK_ARRAY_COUNT(gRegionIterMethods)); } + +SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) { + return GetSkRegion(env, regionObj); +} + +} // namespace android diff --git a/core/jni/android/graphics/Region.h b/core/jni/android/graphics/Region.h new file mode 100644 index 000000000000..c15f06edd3cb --- /dev/null +++ b/core/jni/android/graphics/Region.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#ifndef _ANDROID_GRAPHICS_REGION_H +#define _ANDROID_GRAPHICS_REGION_H + +#include "jni.h" +#include "SkRegion.h" + +namespace android { + +/* Gets the underlying SkRegion from a Region object. */ +extern SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj); + +} // namespace android + +#endif // _ANDROID_GRAPHICS_REGION_H diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp index c1229f302977..88de94fe3f2d 100644 --- a/core/jni/android/graphics/SurfaceTexture.cpp +++ b/core/jni/android/graphics/SurfaceTexture.cpp @@ -25,8 +25,8 @@ #include <utils/Log.h> #include <utils/misc.h> -#include "android/graphics/GraphicsJNI.h" #include "jni.h" +#include "JNIHelp.h" // ---------------------------------------------------------------------------- @@ -35,57 +35,127 @@ namespace android { static const char* const OutOfResourcesException = "android/graphics/SurfaceTexture$OutOfResourcesException"; -struct st_t { - jfieldID surfaceTexture; +struct fields_t { + jfieldID surfaceTexture; + jmethodID postEvent; }; -static st_t st; +static fields_t fields; // ---------------------------------------------------------------------------- -static void setSurfaceTexture(JNIEnv* env, jobject clazz, +static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz, const sp<SurfaceTexture>& surfaceTexture) { SurfaceTexture* const p = - (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture); + (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture); if (surfaceTexture.get()) { - surfaceTexture->incStrong(clazz); + surfaceTexture->incStrong(thiz); } if (p) { - p->decStrong(clazz); + p->decStrong(thiz); } - env->SetIntField(clazz, st.surfaceTexture, (int)surfaceTexture.get()); + env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get()); } -sp<SurfaceTexture> getSurfaceTexture(JNIEnv* env, jobject clazz) +sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) { sp<SurfaceTexture> surfaceTexture( - (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture)); + (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture)); return surfaceTexture; } // ---------------------------------------------------------------------------- -static void SurfaceTexture_init(JNIEnv* env, jobject clazz, jint texName) +class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener { - sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName)); +public: + JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz); + virtual ~JNISurfaceTextureContext(); + virtual void onFrameAvailable(); + +private: + jobject mWeakThiz; + jclass mClazz; +}; + +JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env, + jobject weakThiz, jclass clazz) : + mWeakThiz(env->NewGlobalRef(weakThiz)), + mClazz((jclass)env->NewGlobalRef(clazz)) +{} + +JNISurfaceTextureContext::~JNISurfaceTextureContext() +{ + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->DeleteGlobalRef(mWeakThiz); + env->DeleteGlobalRef(mClazz); +} + +void JNISurfaceTextureContext::onFrameAvailable() +{ + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz); +} + +// ---------------------------------------------------------------------------- + +static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz) +{ + fields.surfaceTexture = env->GetFieldID(clazz, + ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I"); + if (fields.surfaceTexture == NULL) { + LOGE("can't find android/graphics/SurfaceTexture.%s", + ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID); + } + + fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative", + "(Ljava/lang/Object;)V"); + if (fields.postEvent == NULL) { + LOGE("can't find android/graphics/SurfaceTexture.postEventFromNative"); + } + +} +static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName, + jobject weakThiz) +{ + sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName)); if (surfaceTexture == 0) { - doThrow(env, OutOfResourcesException); + jniThrowException(env, OutOfResourcesException, + "Unable to create native SurfaceTexture"); + return; + } + SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture); + + jclass clazz = env->GetObjectClass(thiz); + if (clazz == NULL) { + jniThrowRuntimeException(env, + "Can't find android/graphics/SurfaceTexture"); return; } - setSurfaceTexture(env, clazz, surfaceTexture); + + sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz, + clazz)); + surfaceTexture->setFrameAvailableListener(ctx); +} + +static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz) +{ + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + surfaceTexture->setFrameAvailableListener(0); + SurfaceTexture_setSurfaceTexture(env, thiz, 0); } -static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject clazz) +static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz) { - sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); surfaceTexture->updateTexImage(); } -static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject clazz, +static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz, jfloatArray jmtx) { - sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); float* mtx = env->GetFloatArrayElements(jmtx, NULL); surfaceTexture->getTransformMatrix(mtx); env->ReleaseFloatArrayElements(jmtx, mtx, 0); @@ -94,21 +164,15 @@ static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject clazz, // ---------------------------------------------------------------------------- const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture"; -static void nativeClassInit(JNIEnv* env, jclass clazz); static JNINativeMethod gSurfaceTextureMethods[] = { - {"nativeClassInit", "()V", (void*)nativeClassInit }, - {"init", "(I)V", (void*)SurfaceTexture_init }, - {"updateTexImage", "()V", (void*)SurfaceTexture_updateTexImage }, - {"getTransformMatrixImpl", "([F)V", (void*)SurfaceTexture_getTransformMatrix }, + {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit }, + {"nativeInit", "(ILjava/lang/Object;)V", (void*)SurfaceTexture_init }, + {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize }, + {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage }, + {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix }, }; -static void nativeClassInit(JNIEnv* env, jclass clazz) -{ - st.surfaceTexture = env->GetFieldID(clazz, - ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I"); -} - int register_android_graphics_SurfaceTexture(JNIEnv* env) { int err = 0; diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index b0338787d5f3..0430a819d02d 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -500,8 +500,9 @@ struct NativeCode : public ANativeActivity { void* dlhandle; ANativeActivity_createFunc* createActivityFunc; - String8 internalDataPath; - String8 externalDataPath; + String8 internalDataPathObj; + String8 externalDataPathObj; + String8 obbPathObj; sp<ANativeWindow> nativeWindow; int32_t lastWindowWidth; @@ -641,8 +642,8 @@ static int mainWorkCallback(int fd, int events, void* data) { static jint loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName, - jobject messageQueue, - jstring internalDataDir, jstring externalDataDir, int sdkVersion, + jobject messageQueue, jstring internalDataDir, jstring obbDir, + jstring externalDataDir, int sdkVersion, jobject jAssetMgr, jbyteArray savedState) { LOG_TRACE("loadNativeCode_native"); @@ -699,19 +700,24 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName code->clazz = env->NewGlobalRef(clazz); const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL); - code->internalDataPath = dirStr; - code->internalDataPath = code->internalDataPath.string(); - env->ReleaseStringUTFChars(path, dirStr); + code->internalDataPathObj = dirStr; + code->internalDataPath = code->internalDataPathObj.string(); + env->ReleaseStringUTFChars(internalDataDir, dirStr); dirStr = env->GetStringUTFChars(externalDataDir, NULL); - code->externalDataPath = dirStr; - code->externalDataPath = code->externalDataPath.string(); - env->ReleaseStringUTFChars(path, dirStr); + code->externalDataPathObj = dirStr; + code->externalDataPath = code->externalDataPathObj.string(); + env->ReleaseStringUTFChars(externalDataDir, dirStr); code->sdkVersion = sdkVersion; code->assetManager = assetManagerForJavaObject(env, jAssetMgr); + dirStr = env->GetStringUTFChars(obbDir, NULL); + code->obbPathObj = dirStr; + code->obbPath = code->obbPathObj.string(); + env->ReleaseStringUTFChars(obbDir, dirStr); + jbyte* rawSavedState = NULL; jsize rawSavedSize = 0; if (savedState != NULL) { @@ -1022,7 +1028,7 @@ finishPreDispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, } static const JNINativeMethod g_methods[] = { - { "loadNativeCode", "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I", + { "loadNativeCode", "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I", (void*)loadNativeCode_native }, { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native }, { "onStartNative", "(I)V", (void*)onStart_native }, diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java index 3eb0b03d4cc1..64c209a38801 100644 --- a/graphics/java/android/graphics/SurfaceTexture.java +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -16,6 +16,11 @@ package android.graphics; +import java.lang.ref.WeakReference; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + /** * Captures frames from an image stream as an OpenGL ES texture. * @@ -32,6 +37,9 @@ package android.graphics; */ public class SurfaceTexture { + private EventHandler mEventHandler; + private OnFrameAvailableListener mOnFrameAvailableListener; + @SuppressWarnings("unused") private int mSurfaceTexture; @@ -59,7 +67,15 @@ public class SurfaceTexture { * @param texName the OpenGL texture object name (e.g. generated via glGenTextures) */ public SurfaceTexture(int texName) { - init(texName); + Looper looper; + if ((looper = Looper.myLooper()) != null) { + mEventHandler = new EventHandler(looper); + } else if ((looper = Looper.getMainLooper()) != null) { + mEventHandler = new EventHandler(looper); + } else { + mEventHandler = null; + } + nativeInit(texName, new WeakReference<SurfaceTexture>(this)); } /** @@ -69,7 +85,7 @@ public class SurfaceTexture { * thread invoking the callback. */ public void setOnFrameAvailableListener(OnFrameAvailableListener l) { - // TODO: Implement this! + mOnFrameAvailableListener = l; } /** @@ -77,8 +93,9 @@ public class SurfaceTexture { * called while the OpenGL ES context that owns the texture is bound to the thread. It will * implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target. */ - public native void updateTexImage(); - + public void updateTexImage() { + nativeUpdateTexImage(); + } /** * Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by @@ -99,12 +116,48 @@ public class SurfaceTexture { if (mtx.length != 16) { throw new IllegalArgumentException(); } - getTransformMatrixImpl(mtx); + nativeGetTransformMatrix(mtx); } - private native void getTransformMatrixImpl(float[] mtx); + protected void finalize() throws Throwable { + try { + nativeFinalize(); + } finally { + super.finalize(); + } + } + + private class EventHandler extends Handler { + public EventHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + if (mOnFrameAvailableListener != null) { + mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this); + } + return; + } + } + + private static void postEventFromNative(Object selfRef) { + WeakReference weakSelf = (WeakReference)selfRef; + SurfaceTexture st = (SurfaceTexture)weakSelf.get(); + if (st == null) { + return; + } + + if (st.mEventHandler != null) { + Message m = st.mEventHandler.obtainMessage(); + st.mEventHandler.sendMessage(m); + } + } - private native void init(int texName); + private native void nativeInit(int texName, Object weakSelf); + private native void nativeFinalize(); + private native void nativeGetTransformMatrix(float[] mtx); + private native void nativeUpdateTexImage(); /* * We use a class initializer to allow the native code to cache some diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 002e48b6d925..79c33f54f559 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -40,6 +40,10 @@ public: enum { MIN_BUFFER_SLOTS = 3 }; enum { NUM_BUFFER_SLOTS = 32 }; + struct FrameAvailableListener : public virtual RefBase { + virtual void onFrameAvailable() = 0; + }; + // tex indicates the name OpenGL texture to which images are to be streamed. // This texture name cannot be changed once the SurfaceTexture is created. SurfaceTexture(GLuint tex); @@ -93,6 +97,10 @@ public: // functions. void getTransformMatrix(float mtx[16]); + // setFrameAvailableListener sets the listener object that will be notified + // when a new frame becomes available. + void setFrameAvailableListener(const sp<FrameAvailableListener>& l); + private: // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for @@ -195,6 +203,11 @@ private: // to a buffer, but other processes do. Vector<sp<GraphicBuffer> > mAllocdBuffers; + // mFrameAvailableListener is the listener object that will be called when a + // new frame becomes available. If it is not NULL it will be called from + // queueBuffer. + sp<FrameAvailableListener> mFrameAvailableListener; + // mMutex is the mutex used to prevent concurrent access to the member // variables of SurfaceTexture objects. It must be locked whenever the // member variables are accessed. diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 447de76508cd..1dadd5389154 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -166,6 +166,9 @@ status_t SurfaceTexture::queueBuffer(int buf) { mLastQueued = buf; mLastQueuedCrop = mNextCrop; mLastQueuedTransform = mNextTransform; + if (mFrameAvailableListener != 0) { + mFrameAvailableListener->onFrameAvailable(); + } return OK; } @@ -237,43 +240,68 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) { LOGV("SurfaceTexture::updateTexImage"); Mutex::Autolock lock(mMutex); - float* xform = mtxIdentity; - switch (mCurrentTransform) { - case 0: - xform = mtxIdentity; - break; - case NATIVE_WINDOW_TRANSFORM_FLIP_H: - xform = mtxFlipH; - break; - case NATIVE_WINDOW_TRANSFORM_FLIP_V: - xform = mtxFlipV; - break; - case NATIVE_WINDOW_TRANSFORM_ROT_90: - xform = mtxRot90; - break; - case NATIVE_WINDOW_TRANSFORM_ROT_180: - xform = mtxRot180; - break; - case NATIVE_WINDOW_TRANSFORM_ROT_270: - xform = mtxRot270; - break; - default: - LOGE("getTransformMatrix: unknown transform: %d", mCurrentTransform); + float xform[16]; + for (int i = 0; i < 16; i++) { + xform[i] = mtxIdentity[i]; + } + if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { + float result[16]; + mtxMul(result, xform, mtxFlipH); + for (int i = 0; i < 16; i++) { + xform[i] = result[i]; + } + } + if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { + float result[16]; + mtxMul(result, xform, mtxFlipV); + for (int i = 0; i < 16; i++) { + xform[i] = result[i]; + } + } + if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + float result[16]; + mtxMul(result, xform, mtxRot90); + for (int i = 0; i < 16; i++) { + xform[i] = result[i]; + } } sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer); - float tx = float(mCurrentCrop.left) / float(buf->getWidth()); - float ty = float(mCurrentCrop.bottom) / float(buf->getHeight()); - float sx = float(mCurrentCrop.width()) / float(buf->getWidth()); - float sy = float(mCurrentCrop.height()) / float(buf->getHeight()); + float tx, ty, sx, sy; + if (!mCurrentCrop.isEmpty()) { + tx = float(mCurrentCrop.left) / float(buf->getWidth()); + ty = float(buf->getHeight() - mCurrentCrop.bottom) / + float(buf->getHeight()); + sx = float(mCurrentCrop.width()) / float(buf->getWidth()); + sy = float(mCurrentCrop.height()) / float(buf->getHeight()); + } else { + tx = 0.0f; + ty = 0.0f; + sx = 1.0f; + sy = 1.0f; + } float crop[16] = { - sx, 0, 0, sx*tx, - 0, sy, 0, sy*ty, + sx, 0, 0, 0, + 0, sy, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 1, + sx*tx, sy*ty, 0, 1, }; - mtxMul(mtx, crop, xform); + float mtxBeforeFlipV[16]; + mtxMul(mtxBeforeFlipV, crop, xform); + + // SurfaceFlinger expects the top of its window textures to be at a Y + // coordinate of 0, so SurfaceTexture must behave the same way. We don't + // want to expose this to applications, however, so we must add an + // additional vertical flip to the transform after all the other transforms. + mtxMul(mtx, mtxFlipV, mtxBeforeFlipV); +} + +void SurfaceTexture::setFrameAvailableListener( + const sp<FrameAvailableListener>& l) { + LOGV("SurfaceTexture::setFrameAvailableListener"); + Mutex::Autolock lock(mMutex); + mFrameAvailableListener = l; } void SurfaceTexture::freeAllBuffers() { diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index 6e4c22eab230..41c9fe2d016c 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -212,6 +212,7 @@ void Allocation::update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff, GLenum type = mType->getElement()->getComponent().getGLType(); GLenum format = mType->getElement()->getComponent().getGLFormat(); GLenum target = (GLenum)getGLTarget(); + rsAssert(mTextureID); glBindTexture(target, mTextureID); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GLenum t = GL_TEXTURE_2D; diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp index 1c6c5ac426bb..001ac5529e20 100644 --- a/libs/rs/rsThreadIO.cpp +++ b/libs/rs/rsThreadIO.cpp @@ -53,6 +53,10 @@ bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand) { waitForCommand = false; //LOGV("playCoreCommands 3 %i %i", cmdID, cmdSize); + if (cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) { + rsAssert(cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *))); + LOGE("playCoreCommands error con %p, cmd %i", con, cmdID); + } gPlaybackFuncs[cmdID](con, data); mToCore.next(); } diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c index 1e468bb985e4..4ac5b7fce136 100644 --- a/libs/rs/rsg_generator.c +++ b/libs/rs/rsg_generator.c @@ -219,7 +219,7 @@ void printPlaybackCpp(FILE *f) { fprintf(f, "};\n\n"); } - fprintf(f, "RsPlaybackFunc gPlaybackFuncs[] = {\n"); + fprintf(f, "RsPlaybackFunc gPlaybackFuncs[%i] = {\n", apiCount + 1); fprintf(f, " NULL,\n"); for (ct=0; ct < apiCount; ct++) { fprintf(f, " %s%s,\n", "rsp_", apis[ct].name); @@ -265,7 +265,7 @@ int main(int argc, char **argv) { printFuncDecls(f, "rsi_", 1); printPlaybackFuncs(f, "rsp_"); fprintf(f, "\n\ntypedef void (*RsPlaybackFunc)(Context *, const void *);\n"); - fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[];\n"); + fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[%i];\n", apiCount + 1); fprintf(f, "}\n"); fprintf(f, "}\n"); diff --git a/native/android/looper.cpp b/native/android/looper.cpp index 9f5cda9a9e98..615493fe9a6c 100644 --- a/native/android/looper.cpp +++ b/native/android/looper.cpp @@ -19,9 +19,11 @@ #include <android/looper.h> #include <utils/Looper.h> +#include <binder/IPCThreadState.h> using android::Looper; using android::sp; +using android::IPCThreadState; ALooper* ALooper_forThread() { return Looper::getForThread().get(); @@ -46,6 +48,7 @@ int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa return ALOOPER_POLL_ERROR; } + IPCThreadState::self()->flushCommands(); return looper->pollOnce(timeoutMillis, outFd, outEvents, outData); } @@ -55,7 +58,8 @@ int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outDat LOGE("ALooper_pollAll: No looper for this thread!"); return ALOOPER_POLL_ERROR; } - + + IPCThreadState::self()->flushCommands(); return looper->pollAll(timeoutMillis, outFd, outEvents, outData); } diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h index d89bc8b9b6d3..a361846ea416 100644 --- a/native/include/android/native_activity.h +++ b/native/include/android/native_activity.h @@ -91,6 +91,13 @@ typedef struct ANativeActivity { * uses this to access binary assets bundled inside its own .apk file. */ AAssetManager* assetManager; + + /** + * Available starting with Honeycomb: path to the directory containing + * the application's OBB files (if any). If the app doesn't have any + * OBB files, this directory may not exist. + */ + const char* obbPath; } ANativeActivity; /** diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 386cc5d05268..ed3617182cf4 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -62,6 +62,8 @@ static char const * const gExtensionString = "EGL_KHR_image_base " "EGL_KHR_image_pixmap " "EGL_KHR_gl_texture_2D_image " + "EGL_KHR_gl_texture_cubemap_image " + "EGL_KHR_gl_renderbuffer_image " "EGL_KHR_fence_sync " "EGL_ANDROID_image_native_buffer " "EGL_ANDROID_swap_rectangle " @@ -1471,6 +1473,29 @@ EGLint eglGetError(void) return result; } +// Note: Similar implementations of these functions also exist in +// gl2.cpp and gl.cpp, and are used by applications that call the +// exported entry points directly. +typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); +typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); + +static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL; +static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL; + +static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image) +{ + GLeglImageOES implImage = + (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); + glEGLImageTargetTexture2DOES_impl(target, implImage); +} + +static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image) +{ + GLeglImageOES implImage = + (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); + glEGLImageTargetRenderbufferStorageOES_impl(target, implImage); +} + __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) { // eglGetProcAddress() could be the very first function called @@ -1531,6 +1556,16 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) } if (found) { addr = gExtensionForwarders[slot]; + + if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) { + glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr; + addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper; + } + if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) { + glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr; + addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper; + } + gGLExtentionMap.add(name, addr); gGLExtentionSlot++; } diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java index 79fbe0e79f12..1b810d5832bb 100644 --- a/policy/src/com/android/internal/policy/impl/LockScreen.java +++ b/policy/src/com/android/internal/policy/impl/LockScreen.java @@ -311,8 +311,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, setFocusableInTouchMode(true); setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - updateMonitor.registerInfoCallback(this); - updateMonitor.registerSimStateCallback(this); + mUpdateMonitor.registerInfoCallback(this); + mUpdateMonitor.registerSimStateCallback(this); mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mSilentMode = isSilentMode(); @@ -414,6 +414,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { if (DBG) Log.d(TAG, "onRefreshBatteryInfo(" + showBatteryInfo + ", " + pluggedIn + ")"); + + mStatusView.onRefreshBatteryInfo(showBatteryInfo, pluggedIn, batteryLevel); + mShowingBatteryInfo = showBatteryInfo; mPluggedIn = pluggedIn; mBatteryLevel = batteryLevel; diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java index b789288051c7..eb4d930e3f85 100644 --- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -135,9 +135,12 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen // numeric keys. if (mIsAlpha) { mPasswordEntry.setKeyListener(TextKeyListener.getInstance()); + mStatusView.setHelpMessage(R.string.keyguard_password_enter_password_code, + StatusView.LOCK_ICON); } else { mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance()); - mStatusView.setInstructionText(R.string.keyguard_password_enter_pin_password_code); + mStatusView.setHelpMessage(R.string.keyguard_password_enter_pin_code, + StatusView.LOCK_ICON); } mKeyboardHelper.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ? @@ -151,6 +154,11 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mStatusView.setCarrierText(LockScreen.getCarrierString( mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn())); + + mUpdateMonitor.registerInfoCallback(this); + //mUpdateMonitor.registerSimStateCallback(this); + + resetStatusInfo(); } @Override @@ -204,6 +212,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen if (mLockPatternUtils.checkPassword(entry)) { mCallback.keyguardDone(true); mCallback.reportSuccessfulUnlockAttempt(); + mStatusView.setInstructionText(null); } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) { // to avoid accidental lockout, only count attempts that are long enough to be a // real password. This may require some tweaking. @@ -316,11 +325,8 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen } private void resetStatusInfo() { - if(mIsAlpha) { - mStatusView.setInstructionText(R.string.keyguard_password_enter_password_code); - } else { - mStatusView.setInstructionText(R.string.keyguard_password_enter_pin_password_code); - } + mStatusView.setInstructionText(null); + mStatusView.updateStatusLines(true); } } diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java index 5d1455e5b935..6815d5080c21 100644 --- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java +++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java @@ -169,6 +169,9 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient } mStatusView = new StatusView(this, mUpdateMonitor, mLockPatternUtils); + // This shows up when no other information is required on status1 + mStatusView.setHelpMessage(R.string.lockscreen_pattern_instructions, + StatusView.LOCK_ICON); mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); @@ -216,8 +219,8 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient // assume normal footer mode for now updateFooter(FooterMode.Normal); - updateMonitor.registerInfoCallback(this); - updateMonitor.registerSimStateCallback(this); + mUpdateMonitor.registerInfoCallback(this); + mUpdateMonitor.registerSimStateCallback(this); setFocusableInTouchMode(true); // until we get an update... diff --git a/policy/src/com/android/internal/policy/impl/StatusView.java b/policy/src/com/android/internal/policy/impl/StatusView.java index 1caf0b724022..4b91b6564bd4 100644 --- a/policy/src/com/android/internal/policy/impl/StatusView.java +++ b/policy/src/com/android/internal/policy/impl/StatusView.java @@ -19,10 +19,10 @@ import android.view.View; import android.widget.TextView; class StatusView { - private static final int LOCK_ICON = R.drawable.ic_lock_idle_lock; - private static final int ALARM_ICON = R.drawable.ic_lock_idle_alarm; - private static final int CHARGING_ICON = R.drawable.ic_lock_idle_charging; - private static final int BATTERY_LOW_ICON = R.drawable.ic_lock_idle_low_battery; + public static final int LOCK_ICON = R.drawable.ic_lock_idle_lock; + public static final int ALARM_ICON = R.drawable.ic_lock_idle_alarm; + public static final int CHARGING_ICON = R.drawable.ic_lock_idle_charging; + public static final int BATTERY_LOW_ICON = R.drawable.ic_lock_idle_low_battery; private String mDateFormatString; @@ -49,6 +49,8 @@ class StatusView { private TextView mAlarmStatus; private LockPatternUtils mLockPatternUtils; + private int mHelpMessageId; + private int mHelpIconId; private View findViewById(int id) { return mView.findViewById(id); @@ -123,13 +125,13 @@ class StatusView { void setInstructionText(int stringId) { mStatus1.setText(stringId); mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0, 0, 0); - mStatus1.setVisibility(View.VISIBLE); + mStatus1.setVisibility(stringId != 0 ? View.VISIBLE : View.INVISIBLE); } void setInstructionText(String string) { mStatus1.setText(string); mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0, 0, 0); - mStatus1.setVisibility(View.VISIBLE); + mStatus1.setVisibility(TextUtils.isEmpty(string) ? View.INVISIBLE : View.VISIBLE); } void setCarrierText(int stringId) { @@ -148,8 +150,8 @@ class StatusView { */ void updateStatusLines(boolean showStatusLines) { if (!showStatusLines) { - mStatus1.setVisibility(showStatusLines ? View.VISIBLE : View.GONE); - mAlarmStatus.setVisibility(showStatusLines ? View.VISIBLE : View.GONE); + mStatus1.setVisibility(showStatusLines ? View.VISIBLE : View.INVISIBLE); + mAlarmStatus.setVisibility(showStatusLines ? View.VISIBLE : View.INVISIBLE); return; } @@ -171,15 +173,14 @@ class StatusView { mAlarmStatus.setText(nextAlarm); mAlarmStatus.setVisibility(View.VISIBLE); } else { - mAlarmStatus.setVisibility(View.GONE); + mAlarmStatus.setVisibility(View.INVISIBLE); } // Update Status1 - if (mInstructions != null) { + if (!TextUtils.isEmpty(mInstructions)) { // Instructions only - final int resId = TextUtils.isEmpty(mInstructions) ? 0 : LOCK_ICON; mStatus1.setText(mInstructions); - mStatus1.setCompoundDrawablesWithIntrinsicBounds(resId, 0, 0, 0); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0, 0, 0); mStatus1.setVisibility(View.VISIBLE); } else if (mShowingBatteryInfo) { // Battery status @@ -199,13 +200,22 @@ class StatusView { } mStatus1.setVisibility(View.VISIBLE); } else { - // nothing specific to show; show general instructions - mStatus1.setText(R.string.lockscreen_pattern_instructions); - mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0,0, 0); - mStatus1.setVisibility(View.VISIBLE); + // nothing specific to show; show help message and icon, if provided + if (mHelpMessageId != 0) { + mStatus1.setText(mHelpMessageId); + mStatus1.setCompoundDrawablesWithIntrinsicBounds(mHelpIconId, 0,0, 0); + mStatus1.setVisibility(View.VISIBLE); + } else { + mStatus1.setVisibility(View.INVISIBLE); + } } } + void setHelpMessage(int messageId, int iconId) { + mHelpMessageId = messageId; + mHelpIconId = iconId; + } + void refreshTimeAndDateDisplay() { if (mHasDate) { mDate.setText(DateFormat.format(mDateFormatString, new Date())); diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index b5a4bd2da0c7..e314145112bf 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -154,6 +154,24 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount, return true; } +static void dumpRegion(String8& dump, const SkRegion& region) { + if (region.isEmpty()) { + dump.append("<empty>"); + return; + } + + bool first = true; + for (SkRegion::Iterator it(region); !it.done(); it.next()) { + if (first) { + first = false; + } else { + dump.append("|"); + } + const SkIRect& rect = it.rect(); + dump.appendFormat("[%d,%d][%d,%d]", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); + } +} + // --- InputDispatcher --- @@ -495,7 +513,7 @@ const InputWindow* InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t if (!(flags & InputWindow::FLAG_NOT_TOUCHABLE)) { bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || window->touchableAreaContainsPoint(x, y)) { + if (isTouchModal || window->touchableRegionContainsPoint(x, y)) { // Found window. return window; } @@ -1188,7 +1206,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) { bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || window->touchableAreaContainsPoint(x, y)) { + if (isTouchModal || window->touchableRegionContainsPoint(x, y)) { if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) { newTouchedWindow = window; } @@ -2884,9 +2902,7 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, " "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " "frame=[%d,%d][%d,%d], " - "visibleFrame=[%d,%d][%d,%d], " - "touchableArea=[%d,%d][%d,%d], " - "ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", + "touchableRegion=", i, window.name.string(), toString(window.paused), toString(window.hasFocus), @@ -2896,11 +2912,9 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { window.layoutParamsFlags, window.layoutParamsType, window.layer, window.frameLeft, window.frameTop, - window.frameRight, window.frameBottom, - window.visibleFrameLeft, window.visibleFrameTop, - window.visibleFrameRight, window.visibleFrameBottom, - window.touchableAreaLeft, window.touchableAreaTop, - window.touchableAreaRight, window.touchableAreaBottom, + window.frameRight, window.frameBottom); + dumpRegion(dump, window.touchableRegion); + dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", window.ownerPid, window.ownerUid, window.dispatchingTimeout / 1000000.0); } diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp index 9ce45f50513c..b552f6d5b43d 100644 --- a/services/input/InputWindow.cpp +++ b/services/input/InputWindow.cpp @@ -24,9 +24,8 @@ namespace android { // --- InputWindow --- -bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const { - return x >= touchableAreaLeft && x <= touchableAreaRight - && y >= touchableAreaTop && y <= touchableAreaBottom; +bool InputWindow::touchableRegionContainsPoint(int32_t x, int32_t y) const { + return touchableRegion.contains(x, y); } bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const { diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h index b3d5a651ba75..9c43067363a9 100644 --- a/services/input/InputWindow.h +++ b/services/input/InputWindow.h @@ -23,6 +23,8 @@ #include <utils/Timers.h> #include <utils/String8.h> +#include <SkRegion.h> + #include "InputApplication.h" namespace android { @@ -129,14 +131,7 @@ struct InputWindow { int32_t frameTop; int32_t frameRight; int32_t frameBottom; - int32_t visibleFrameLeft; - int32_t visibleFrameTop; - int32_t visibleFrameRight; - int32_t visibleFrameBottom; - int32_t touchableAreaLeft; - int32_t touchableAreaTop; - int32_t touchableAreaRight; - int32_t touchableAreaBottom; + SkRegion touchableRegion; bool visible; bool canReceiveKeys; bool hasFocus; @@ -146,7 +141,7 @@ struct InputWindow { int32_t ownerPid; int32_t ownerUid; - bool touchableAreaContainsPoint(int32_t x, int32_t y) const; + bool touchableRegionContainsPoint(int32_t x, int32_t y) const; bool frameContainsPoint(int32_t x, int32_t y) const; /* Returns true if the window is of a trusted type that is allowed to silently diff --git a/services/java/com/android/server/InputWindow.java b/services/java/com/android/server/InputWindow.java index 1515290145d8..2c2cdfe8ae77 100644 --- a/services/java/com/android/server/InputWindow.java +++ b/services/java/com/android/server/InputWindow.java @@ -16,6 +16,7 @@ package com.android.server; +import android.graphics.Region; import android.view.InputChannel; /** @@ -39,23 +40,14 @@ public final class InputWindow { // Dispatching timeout. public long dispatchingTimeoutNanos; - // Window frame area. + // Window frame. public int frameLeft; public int frameTop; public int frameRight; public int frameBottom; - // Window visible frame area. - public int visibleFrameLeft; - public int visibleFrameTop; - public int visibleFrameRight; - public int visibleFrameBottom; - - // Window touchable area. - public int touchableAreaLeft; - public int touchableAreaTop; - public int touchableAreaRight; - public int touchableAreaBottom; + // Window touchable region. + public final Region touchableRegion = new Region(); // Window is visible. public boolean visible; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 6f4b4c5be403..978946f546a3 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -204,11 +204,9 @@ class ServerThread extends Thread { // TODO: Use a more reliable check to see if this product should // support Bluetooth - see bug 988521 if (SystemProperties.get("ro.kernel.qemu").equals("1")) { - Slog.i(TAG, "Registering null Bluetooth Service (emulator)"); - ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null); + Slog.i(TAG, "No Bluetooh Service (emulator)"); } else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) { - Slog.i(TAG, "Registering null Bluetooth Service (factory test)"); - ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null); + Slog.i(TAG, "No Bluetooth Service (factory test)"); } else { Slog.i(TAG, "Bluetooth Service"); bluetooth = new BluetoothService(context); diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index bdc779c3e11e..1b3725c4d051 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -520,7 +520,7 @@ public class WindowManagerService extends IWindowManager.Stub int mRotation; int mAnimFlags; - private final Rect tmpRect = new Rect(); + private final Region mTmpRegion = new Region(); DragState(IBinder token, Surface surface, int flags, IBinder localWin) { mToken = token; @@ -816,31 +816,13 @@ public class WindowManagerService extends IWindowManager.Stub // not touchable == don't tell about drags continue; } - // account for the window's decor etc - tmpRect.set(child.mFrame); - if (child.mTouchableInsets == ViewTreeObserver - .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) { - // The point is inside of the window if it is - // inside the frame, AND the content part of that - // frame that was given by the application. - tmpRect.left += child.mGivenContentInsets.left; - tmpRect.top += child.mGivenContentInsets.top; - tmpRect.right -= child.mGivenContentInsets.right; - tmpRect.bottom -= child.mGivenContentInsets.bottom; - } else if (child.mTouchableInsets == ViewTreeObserver - .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) { - // The point is inside of the window if it is - // inside the frame, AND the visible part of that - // frame that was given by the application. - tmpRect.left += child.mGivenVisibleInsets.left; - tmpRect.top += child.mGivenVisibleInsets.top; - tmpRect.right -= child.mGivenVisibleInsets.right; - tmpRect.bottom -= child.mGivenVisibleInsets.bottom; - } + + child.getTouchableRegion(mTmpRegion); + final int touchFlags = flags & - (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); - if (tmpRect.contains(x, y) || touchFlags == 0) { + (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); + if (mTmpRegion.contains(x, y) || touchFlags == 0) { // Found it touchedWin = child; break; @@ -2667,7 +2649,7 @@ public class WindowManagerService extends IWindowManager.Stub void setInsetsWindow(Session session, IWindow client, int touchableInsets, Rect contentInsets, - Rect visibleInsets) { + Rect visibleInsets, Region touchableRegion) { long origId = Binder.clearCallingIdentity(); try { synchronized (mWindowMap) { @@ -2676,6 +2658,7 @@ public class WindowManagerService extends IWindowManager.Stub w.mGivenInsetsPending = false; w.mGivenContentInsets.set(contentInsets); w.mGivenVisibleInsets.set(visibleInsets); + w.mGivenTouchableRegion.set(touchableRegion); w.mTouchableInsets = touchableInsets; mLayoutNeeded = true; performLayoutAndPlaceSurfacesLocked(); @@ -5882,7 +5865,7 @@ public class WindowManagerService extends IWindowManager.Stub final InputWindow inputWindow = windowList.add(); inputWindow.inputChannel = mDragState.mServerChannel; inputWindow.name = "drag"; - inputWindow.layoutParamsFlags = 0; + inputWindow.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG; inputWindow.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; inputWindow.visible = true; @@ -5900,15 +5883,8 @@ public class WindowManagerService extends IWindowManager.Stub inputWindow.frameRight = mDisplay.getWidth(); inputWindow.frameBottom = mDisplay.getHeight(); - inputWindow.visibleFrameLeft = inputWindow.frameLeft; - inputWindow.visibleFrameTop = inputWindow.frameTop; - inputWindow.visibleFrameRight = inputWindow.frameRight; - inputWindow.visibleFrameBottom = inputWindow.frameBottom; - - inputWindow.touchableAreaLeft = inputWindow.frameLeft; - inputWindow.touchableAreaTop = inputWindow.frameTop; - inputWindow.touchableAreaRight = inputWindow.frameRight; - inputWindow.touchableAreaBottom = inputWindow.frameBottom; + // The drag window cannot receive new touches. + inputWindow.touchableRegion.setEmpty(); } /* Updates the cached window information provided to the input dispatcher. */ @@ -5973,40 +5949,8 @@ public class WindowManagerService extends IWindowManager.Stub inputWindow.frameTop = frame.top; inputWindow.frameRight = frame.right; inputWindow.frameBottom = frame.bottom; - - final Rect visibleFrame = child.mVisibleFrame; - inputWindow.visibleFrameLeft = visibleFrame.left; - inputWindow.visibleFrameTop = visibleFrame.top; - inputWindow.visibleFrameRight = visibleFrame.right; - inputWindow.visibleFrameBottom = visibleFrame.bottom; - - switch (child.mTouchableInsets) { - default: - case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME: - inputWindow.touchableAreaLeft = frame.left; - inputWindow.touchableAreaTop = frame.top; - inputWindow.touchableAreaRight = frame.right; - inputWindow.touchableAreaBottom = frame.bottom; - break; - - case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: { - Rect inset = child.mGivenContentInsets; - inputWindow.touchableAreaLeft = frame.left + inset.left; - inputWindow.touchableAreaTop = frame.top + inset.top; - inputWindow.touchableAreaRight = frame.right - inset.right; - inputWindow.touchableAreaBottom = frame.bottom - inset.bottom; - break; - } - - case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: { - Rect inset = child.mGivenVisibleInsets; - inputWindow.touchableAreaLeft = frame.left + inset.left; - inputWindow.touchableAreaTop = frame.top + inset.top; - inputWindow.touchableAreaRight = frame.right - inset.right; - inputWindow.touchableAreaBottom = frame.bottom - inset.bottom; - break; - } - } + + child.getTouchableRegion(inputWindow.touchableRegion); } // Send windows to native code. @@ -6516,9 +6460,9 @@ public class WindowManagerService extends IWindowManager.Stub } public void setInsets(IWindow window, int touchableInsets, - Rect contentInsets, Rect visibleInsets) { + Rect contentInsets, Rect visibleInsets, Region touchableArea) { setInsetsWindow(this, window, touchableInsets, contentInsets, - visibleInsets); + visibleInsets, touchableArea); } public void getDisplayFrame(IWindow window, Rect outDisplayFrame) { @@ -6648,7 +6592,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mWindowMap) { long ident = Binder.clearCallingIdentity(); try { - if (mDragState.mToken != token) { + if (mDragState == null || mDragState.mToken != token) { Slog.w(TAG, "Invalid drop-result claim by " + window); throw new IllegalStateException("reportDropResult() by non-recipient"); } @@ -6857,6 +6801,11 @@ public class WindowManagerService extends IWindowManager.Stub final Rect mGivenVisibleInsets = new Rect(); /** + * This is the given touchable area relative to the window frame, or null if none. + */ + final Region mGivenTouchableRegion = new Region(); + + /** * Flag indicating whether the touchable region should be adjusted by * the visible insets; if false the area outside the visible insets is * NOT touchable, so we must use those to adjust the frame during hit @@ -8139,6 +8088,36 @@ public class WindowManagerService extends IWindowManager.Stub return true; } + public void getTouchableRegion(Region outRegion) { + final Rect frame = mFrame; + switch (mTouchableInsets) { + default: + case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME: + outRegion.set(frame); + break; + case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: { + final Rect inset = mGivenContentInsets; + outRegion.set( + frame.left + inset.left, frame.top + inset.top, + frame.right - inset.right, frame.bottom - inset.bottom); + break; + } + case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: { + final Rect inset = mGivenVisibleInsets; + outRegion.set( + frame.left + inset.left, frame.top + inset.top, + frame.right - inset.right, frame.bottom - inset.bottom); + break; + } + case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: { + final Region givenTouchableRegion = mGivenTouchableRegion; + outRegion.set(givenTouchableRegion); + outRegion.translate(frame.left, frame.top); + break; + } + } + } + void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mSession="); pw.print(mSession); pw.print(" mClient="); pw.println(mClient.asBinder()); diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp index a4609a0f9b85..75154567c149 100644 --- a/services/jni/com_android_server_InputWindow.cpp +++ b/services/jni/com_android_server_InputWindow.cpp @@ -21,6 +21,7 @@ #include <android_runtime/AndroidRuntime.h> #include <android_view_InputChannel.h> +#include <android/graphics/Region.h> #include "com_android_server_InputWindow.h" #include "com_android_server_InputWindowHandle.h" @@ -39,14 +40,7 @@ static struct { jfieldID frameTop; jfieldID frameRight; jfieldID frameBottom; - jfieldID visibleFrameLeft; - jfieldID visibleFrameTop; - jfieldID visibleFrameRight; - jfieldID visibleFrameBottom; - jfieldID touchableAreaLeft; - jfieldID touchableAreaTop; - jfieldID touchableAreaRight; - jfieldID touchableAreaBottom; + jfieldID touchableRegion; jfieldID visible; jfieldID canReceiveKeys; jfieldID hasFocus; @@ -108,22 +102,17 @@ void android_server_InputWindow_toNative( gInputWindowClassInfo.frameRight); outInputWindow->frameBottom = env->GetIntField(inputWindowObj, gInputWindowClassInfo.frameBottom); - outInputWindow->visibleFrameLeft = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.visibleFrameLeft); - outInputWindow->visibleFrameTop = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.visibleFrameTop); - outInputWindow->visibleFrameRight = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.visibleFrameRight); - outInputWindow->visibleFrameBottom = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.visibleFrameBottom); - outInputWindow->touchableAreaLeft = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.touchableAreaLeft); - outInputWindow->touchableAreaTop = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.touchableAreaTop); - outInputWindow->touchableAreaRight = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.touchableAreaRight); - outInputWindow->touchableAreaBottom = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.touchableAreaBottom); + + jobject regionObj = env->GetObjectField(inputWindowObj, + gInputWindowClassInfo.touchableRegion); + if (regionObj) { + SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj); + outInputWindow->touchableRegion.set(*region); + env->DeleteLocalRef(regionObj); + } else { + outInputWindow->touchableRegion.setEmpty(); + } + outInputWindow->visible = env->GetBooleanField(inputWindowObj, gInputWindowClassInfo.visible); outInputWindow->canReceiveKeys = env->GetBooleanField(inputWindowObj, @@ -187,29 +176,8 @@ int register_android_server_InputWindow(JNIEnv* env) { GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz, "frameBottom", "I"); - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz, - "visibleFrameLeft", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz, - "visibleFrameTop", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz, - "visibleFrameRight", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz, - "visibleFrameBottom", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz, - "touchableAreaLeft", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz, - "touchableAreaTop", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz, - "touchableAreaRight", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz, - "touchableAreaBottom", "I"); + GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, gInputWindowClassInfo.clazz, + "touchableRegion", "Landroid/graphics/Region;"); GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz, "visible", "Z"); diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index 3b52252e34ae..0b4fc51454b2 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -164,6 +164,11 @@ public class MockContext extends Context { } @Override + public File getObbDir() { + throw new UnsupportedOperationException(); + } + + @Override public File getCacheDir() { throw new UnsupportedOperationException(); } diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk index 9b7bc5f9e26f..a0a7307a8cc0 100644 --- a/tools/layoutlib/bridge/Android.mk +++ b/tools/layoutlib/bridge/Android.mk @@ -20,10 +20,11 @@ LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_JAVA_LIBRARIES := \ kxml2-2.3.0 \ - layoutlib_api-prebuilt \ - ninepatch-prebuilt + layoutlib_api-prebuilt -LOCAL_STATIC_JAVA_LIBRARIES := temp_layoutlib +LOCAL_STATIC_JAVA_LIBRARIES := \ + temp_layoutlib \ + ninepatch-prebuilt LOCAL_MODULE := layoutlib diff --git a/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java b/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java new file mode 100644 index 000000000000..4c500e75cbc8 --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java @@ -0,0 +1,560 @@ +/* + * 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.ide.common.resources; + +import com.android.ide.common.rendering.api.LayoutLog; +import com.android.ide.common.rendering.api.ResourceValue; +import com.android.ide.common.rendering.api.StyleResourceValue; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class ResourceResolver { + + public final static String RES_ANIMATOR = "animator"; + 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_NULL = "@null"; + + private final static String REFERENCE_STYLE = RES_STYLE + "/"; + private final static String PREFIX_ANDROID_RESOURCE_REF = "@android:"; + private final static String PREFIX_RESOURCE_REF = "@"; + private final static String PREFIX_ANDROID_THEME_REF = "?android:"; + private final static String PREFIX_THEME_REF = "?"; + private final static String PREFIX_ANDROID = "android:"; + + + private final IFrameworkResourceIdProvider mFrameworkProvider; + private final Map<String, Map<String, ResourceValue>> mProjectResources; + private final Map<String, Map<String, ResourceValue>> mFrameworkResources; + private final LayoutLog mLogger; + + private final Map<StyleResourceValue, StyleResourceValue> mStyleInheritanceMap = + new HashMap<StyleResourceValue, StyleResourceValue>(); + private StyleResourceValue mTheme; + + public interface IFrameworkResourceIdProvider { + Integer getId(String resType, String resName); + } + + private ResourceResolver( + IFrameworkResourceIdProvider provider, + Map<String, Map<String, ResourceValue>> projectResources, + Map<String, Map<String, ResourceValue>> frameworkResources, + LayoutLog logger) { + mFrameworkProvider = provider; + mProjectResources = projectResources; + mFrameworkResources = frameworkResources; + mLogger = logger; + } + + /** + * Creates a new ResourceResolver object. + * + * @param IFrameworkResourceIdProvider an optional framework resource ID provider + * @param projectResources the project resources. + * @param frameworkResources the framework resources. + * @param themeName the name of the current theme. + * @param isProjectTheme Is this a project theme? + * @return + */ + public static ResourceResolver create( + IFrameworkResourceIdProvider provider, + Map<String, Map<String, ResourceValue>> projectResources, + Map<String, Map<String, ResourceValue>> frameworkResources, + String themeName, boolean isProjectTheme, LayoutLog logger) { + + ResourceResolver resolver = new ResourceResolver(provider, + projectResources, frameworkResources, + logger); + + resolver.computeStyleMaps(themeName, isProjectTheme); + + return resolver; + } + + public StyleResourceValue getTheme() { + return mTheme; + } + + /** + * 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 ResourceValue 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 ResourceValue getProjectResource(String resourceType, String resourceName) { + return getResource(resourceType, resourceName, mProjectResources); + } + + /** + * Returns the {@link ResourceValue} matching a given name in the current theme. If the + * item is not directly available in the theme, the method looks in its parent theme. + * + * @param itemName the name of the item to search for. + * @return the {@link ResourceValue} object or <code>null</code> + */ + public ResourceValue findItemInTheme(String itemName) { + if (mTheme != null) { + return findItemInStyle(mTheme, itemName); + } + + return null; + } + + /** + * Returns the {@link ResourceValue} 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 ResourceValue} object or <code>null</code> + */ + public ResourceValue findItemInStyle(StyleResourceValue style, String itemName) { + ResourceValue item = style.findValue(itemName); + + // if we didn't find it, we look in the parent style (if applicable) + if (item == null && mStyleInheritanceMap != null) { + StyleResourceValue parentStyle = mStyleInheritanceMap.get(style); + if (parentStyle != null) { + return findItemInStyle(parentStyle, itemName); + } + } + + return item; + } + + /** + * Searches for, and returns a {@link ResourceValue} 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 ResourceValue} or <code>null</code>. + */ + public ResourceValue findResValue(String reference, boolean forceFrameworkOnly) { + if (reference == null) { + return null; + } + if (reference.startsWith(PREFIX_THEME_REF)) { + // no theme? no need to go further! + if (mTheme == null) { + return null; + } + + boolean frameworkOnly = false; + + // eliminate the prefix from the string + if (reference.startsWith(PREFIX_ANDROID_THEME_REF)) { + frameworkOnly = true; + reference = reference.substring(PREFIX_ANDROID_THEME_REF.length()); + } else { + reference = reference.substring(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 (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(PREFIX_ANDROID)) { + frameworkOnly = true; + referenceName = referenceName.substring(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(mTheme, referenceName); + } + + return findItemInStyle(mTheme, referenceName); + } else if (reference.startsWith(PREFIX_RESOURCE_REF)) { + boolean frameworkOnly = false; + + // check for the specific null reference value. + if (REFERENCE_NULL.equals(reference)) { + return null; + } + + // Eliminate the prefix from the string. + if (reference.startsWith(PREFIX_ANDROID_RESOURCE_REF)) { + frameworkOnly = true; + reference = reference.substring( + PREFIX_ANDROID_RESOURCE_REF.length()); + } else { + reference = reference.substring(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(PREFIX_ANDROID)) { + frameworkOnly = true; + segments[1] = segments[1].substring(PREFIX_ANDROID.length()); + } + + return findResValue(segments[0], segments[1], + forceFrameworkOnly ? true :frameworkOnly); + } + + // Looks like the value didn't reference anything. Return null. + return null; + } + + /** + * Resolves the value of a resource, if the value references a theme or resource value. + * <p/> + * This method ensures that it returns a {@link ResourceValue} 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 {@link ResourceValue} 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 + * @param isFrameworkValue whether the value is a framework value. + * + * @return the resolved resource value or <code>null</code> if it failed to resolve it. + */ + public ResourceValue resolveValue(String type, String name, String value, + boolean isFrameworkValue) { + if (value == null) { + return null; + } + + // get the ResourceValue referenced by this value + ResourceValue resValue = findResValue(value, isFrameworkValue); + + // if resValue is null, but value is not null, this means it was not a reference. + // we return the name/value wrapper in a ResourceValue. the isFramework flag doesn't + // matter. + if (resValue == null) { + return new ResourceValue(type, name, value, isFrameworkValue); + } + + // we resolved a first reference, but we need to make sure this isn't a reference also. + return resolveResValue(resValue); + } + + /** + * Returns the {@link ResourceValue} referenced by the value of <var>value</var>. + * <p/> + * This method ensures that it returns a {@link ResourceValue} 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 ResourceValue} object or <code>null</code> + */ + public ResourceValue resolveResValue(ResourceValue value) { + if (value == null) { + return null; + } + + // if the resource value is a style, we simply return it. + if (value instanceof StyleResourceValue) { + return value; + } + + // else attempt to find another ResourceValue referenced by this one. + ResourceValue 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 ResourceValue} 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 ResourceValue findResValue(String resType, String resName, boolean frameworkOnly) { + // map of ResouceValue for the given type + Map<String, ResourceValue> typeMap; + + // if allowed, search in the project resources first. + if (frameworkOnly == false) { + typeMap = mProjectResources.get(resType); + if (typeMap != null) { + ResourceValue item = typeMap.get(resName); + if (item != null) { + return item; + } + } + } + + // now search in the framework resources. + typeMap = mFrameworkResources.get(resType); + if (typeMap != null) { + ResourceValue item = typeMap.get(resName); + if (item != null) { + return item; + } + + // if it was not found and the type is an id, it is possible that the ID was + // generated dynamically when compiling the framework resources. + // Look for it in the R map. + if (mFrameworkProvider != null && RES_ID.equals(resType)) { + if (mFrameworkProvider.getId(resType, resName) != null) { + return new ResourceValue(resType, resName, true); + } + } + } + + // didn't find the resource anywhere. + // This is normal if the resource is an ID that is generated automatically. + // For other resources, we output a warning + if ("+id".equals(resType) == false && "+android:id".equals(resType) == false) { //$NON-NLS-1$ //$NON-NLS-2$ + mLogger.warning(LayoutLog.TAG_RESOURCES_RESOLVE, + "Couldn't resolve resource @" + + (frameworkOnly ? "android:" : "") + resType + "/" + resName, + new ResourceValue(resType, resName, frameworkOnly)); + } + return null; + } + + ResourceValue getResource(String resourceType, String resourceName, + Map<String, Map<String, ResourceValue>> resourceRepository) { + Map<String, ResourceValue> typeMap = resourceRepository.get(resourceType); + if (typeMap != null) { + ResourceValue item = typeMap.get(resourceName); + if (item != null) { + item = resolveResValue(item); + return item; + } + } + + // didn't find the resource anywhere. + return null; + + } + + /** + * Compute style information from the given list of style for the project and framework. + * @param themeName the name of the current theme. + * @param isProjectTheme Is this a project theme? + */ + private void computeStyleMaps(String themeName, boolean isProjectTheme) { + Map<String, ResourceValue> projectStyleMap = mProjectResources.get(RES_STYLE); + Map<String, ResourceValue> frameworkStyleMap = mFrameworkResources.get(RES_STYLE); + + if (projectStyleMap != null && frameworkStyleMap != null) { + // first, get the theme + ResourceValue theme = null; + + // project theme names have been prepended with a * + if (isProjectTheme) { + theme = projectStyleMap.get(themeName); + } else { + theme = frameworkStyleMap.get(themeName); + } + + if (theme instanceof StyleResourceValue) { + // compute the inheritance map for both the project and framework styles + computeStyleInheritance(projectStyleMap.values(), projectStyleMap, + frameworkStyleMap); + + // Compute the style inheritance for the framework styles/themes. + // Since, for those, the style parent values do not contain 'android:' + // we want to force looking in the framework style only to avoid using + // similarly named styles from the project. + // To do this, we pass null in lieu of the project style map. + computeStyleInheritance(frameworkStyleMap.values(), null /*inProjectStyleMap */, + frameworkStyleMap); + + mTheme = (StyleResourceValue) theme; + } + } + } + + + + /** + * Compute the parent style for all the styles in a given list. + * @param styles the styles for which we compute the parent. + * @param inProjectStyleMap the map of project styles. + * @param inFrameworkStyleMap the map of framework styles. + * @param outInheritanceMap the map of style inheritance. This is filled by the method. + */ + private void computeStyleInheritance(Collection<ResourceValue> styles, + Map<String, ResourceValue> inProjectStyleMap, + Map<String, ResourceValue> inFrameworkStyleMap) { + for (ResourceValue value : styles) { + if (value instanceof StyleResourceValue) { + StyleResourceValue style = (StyleResourceValue)value; + StyleResourceValue parentStyle = null; + + // first look for a specified parent. + String parentName = style.getParentStyle(); + + // no specified parent? try to infer it from the name of the style. + if (parentName == null) { + parentName = getParentName(value.getName()); + } + + if (parentName != null) { + parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap); + + if (parentStyle != null) { + mStyleInheritanceMap.put(style, parentStyle); + } + } + } + } + } + + + /** + * Computes the name of the parent style, or <code>null</code> if the style is a root style. + */ + private String getParentName(String styleName) { + int index = styleName.lastIndexOf('.'); + if (index != -1) { + return styleName.substring(0, index); + } + + return null; + } + + /** + * Searches for and returns the {@link StyleResourceValue} from a given name. + * <p/>The format of the name can be: + * <ul> + * <li>[android:]<name></li> + * <li>[android:]style/<name></li> + * <li>@[android:]style/<name></li> + * </ul> + * @param parentName the name of the style. + * @param inProjectStyleMap the project style map. Can be <code>null</code> + * @param inFrameworkStyleMap the framework style map. + * @return The matching {@link StyleResourceValue} object or <code>null</code> if not found. + */ + private StyleResourceValue getStyle(String parentName, + Map<String, ResourceValue> inProjectStyleMap, + Map<String, ResourceValue> inFrameworkStyleMap) { + boolean frameworkOnly = false; + + String name = parentName; + + // remove the useless @ if it's there + if (name.startsWith(PREFIX_RESOURCE_REF)) { + name = name.substring(PREFIX_RESOURCE_REF.length()); + } + + // check for framework identifier. + if (name.startsWith(PREFIX_ANDROID)) { + frameworkOnly = true; + name = name.substring(PREFIX_ANDROID.length()); + } + + // at this point we could have the format <type>/<name>. we want only the name as long as + // the type is style. + if (name.startsWith(REFERENCE_STYLE)) { + name = name.substring(REFERENCE_STYLE.length()); + } else if (name.indexOf('/') != -1) { + return null; + } + + ResourceValue parent = null; + + // if allowed, search in the project resources. + if (frameworkOnly == false && inProjectStyleMap != null) { + parent = inProjectStyleMap.get(name); + } + + // if not found, then look in the framework resources. + if (parent == null) { + parent = inFrameworkStyleMap.get(name); + } + + // make sure the result is the proper class type and return it. + if (parent instanceof StyleResourceValue) { + return (StyleResourceValue)parent; + } + + assert false; + mLogger.error(LayoutLog.TAG_RESOURCES_RESOLVE, + String.format("Unable to resolve parent style name: %s", parentName), + null /*data*/); + + return null; + } + + +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java index 194687ebb48d..112af1ea35d2 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java @@ -41,25 +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_ANIMATOR = "animator"; - 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"; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 82e217a677ab..f6332016d73a 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -20,6 +20,7 @@ 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.ide.common.rendering.api.StyleResourceValue; +import com.android.ide.common.resources.ResourceResolver; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.BridgeConstants; import com.android.layoutlib.bridge.impl.Stack; @@ -76,12 +77,9 @@ public final class BridgeContext extends Activity { private Resources mResources; private Theme mTheme; private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>(); - private final StyleResourceValue mThemeValues; private final Object mProjectKey; private final DisplayMetrics mMetrics; - private final Map<String, Map<String, ResourceValue>> mProjectResources; - private final Map<String, Map<String, ResourceValue>> mFrameworkResources; - private final Map<StyleResourceValue, StyleResourceValue> mStyleInheritanceMap; + private final ResourceResolver mResourceResolver; private final Map<Object, Map<String, String>> mDefaultPropMaps = new IdentityHashMap<Object, Map<String,String>>(); @@ -116,19 +114,13 @@ public final class BridgeContext extends Activity { * @param projectCallback */ public BridgeContext(Object projectKey, DisplayMetrics metrics, - StyleResourceValue currentTheme, - Map<String, Map<String, ResourceValue>> projectResources, - Map<String, Map<String, ResourceValue>> frameworkResources, - Map<StyleResourceValue, StyleResourceValue> styleInheritanceMap, + ResourceResolver resourceResolver, IProjectCallback projectCallback) { mProjectKey = projectKey; mMetrics = metrics; mProjectCallback = projectCallback; - mThemeValues = currentTheme; - mProjectResources = projectResources; - mFrameworkResources = frameworkResources; - mStyleInheritanceMap = styleInheritanceMap; + mResourceResolver = resourceResolver; mFragments.mCurState = Fragment.CREATED; mFragments.mActivity = this; @@ -180,6 +172,10 @@ public final class BridgeContext extends Activity { return mProjectCallback; } + public ResourceResolver getResolver() { + return mResourceResolver; + } + public Map<String, String> getDefaultPropMap(Object key) { return mDefaultPropMaps.get(key); } @@ -265,7 +261,7 @@ public final class BridgeContext extends Activity { @Override public final TypedArray obtainStyledAttributes(int[] attrs) { - return createStyleBasedTypedArray(mThemeValues, attrs); + return createStyleBasedTypedArray(mResourceResolver.getTheme(), attrs); } @Override @@ -362,7 +358,8 @@ public final class BridgeContext extends Activity { customStyle = set.getAttributeValue(null /* namespace*/, "style"); } if (customStyle != null) { - ResourceValue item = findResValue(customStyle, false /*forceFrameworkOnly*/); + ResourceValue item = mResourceResolver.findResValue(customStyle, + false /*forceFrameworkOnly*/); if (item instanceof StyleResourceValue) { defStyleValues = (StyleResourceValue)item; @@ -378,22 +375,21 @@ public final class BridgeContext extends Activity { } // look for the style in the current theme, and its parent: - if (mThemeValues != null) { - ResourceValue item = findItemInStyle(mThemeValues, defStyleName); + ResourceValue item = mResourceResolver.findItemInTheme(defStyleName); - if (item != null) { - // item is a reference to a style entry. Search for it. - item = findResValue(item.getValue(), false /*forceFrameworkOnly*/); + if (item != null) { + // item is a reference to a style entry. Search for it. + item = mResourceResolver.findResValue(item.getValue(), + false /*forceFrameworkOnly*/); - if (item instanceof StyleResourceValue) { - defStyleValues = (StyleResourceValue)item; - } - } else { - Bridge.getLog().error(null, - String.format( - "Failed to find style '%s' in current theme", defStyleName), - null /*data*/); + if (item instanceof StyleResourceValue) { + defStyleValues = (StyleResourceValue)item; } + } else { + Bridge.getLog().error(null, + String.format( + "Failed to find style '%s' in current theme", defStyleName), + null /*data*/); } } @@ -425,13 +421,13 @@ public final class BridgeContext extends Activity { // look for the value in the defStyle first (and its parent if needed) if (defStyleValues != null) { - resValue = findItemInStyle(defStyleValues, name); + resValue = mResourceResolver.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 = mResourceResolver.findItemInTheme(name); } // if we found a value, we make sure this doesn't reference another value. @@ -442,14 +438,15 @@ public final class BridgeContext extends Activity { defaultPropMap.put(name, resValue.getValue()); } - resValue = resolveResValue(resValue); + resValue = mResourceResolver.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, isPlatformFile)); + ta.bridgeSetValue(index, name, + mResourceResolver.resolveValue(null, name, value, isPlatformFile)); } } } @@ -487,10 +484,10 @@ public final class BridgeContext extends Activity { String name = styleAttribute.getValue(); // get the value from the style, or its parent styles. - ResourceValue resValue = findItemInStyle(style, name); + ResourceValue resValue = mResourceResolver.findItemInStyle(style, name); // resolve it to make sure there are no references left. - ta.bridgeSetValue(index, name, resolveResValue(resValue)); + ta.bridgeSetValue(index, name, mResourceResolver.resolveResValue(resValue)); } ta.sealArray(); @@ -500,295 +497,6 @@ public final class BridgeContext extends Activity { /** - * Resolves the value of a resource, if the value references a theme or resource value. - * <p/> - * This method ensures that it returns a {@link ResourceValue} 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 {@link ResourceValue} 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 - * @param isFrameworkValue whether the value is a framework value. - * - * @return the resolved resource value or <code>null</code> if it failed to resolve it. - */ - private ResourceValue resolveValue(String type, String name, String value, - boolean isFrameworkValue) { - if (value == null) { - return null; - } - - // get the ResourceValue referenced by this value - ResourceValue resValue = findResValue(value, isFrameworkValue); - - // if resValue is null, but value is not null, this means it was not a reference. - // we return the name/value wrapper in a ResourceValue. the isFramework flag doesn't - // matter. - if (resValue == null) { - return new ResourceValue(type, name, value, isFrameworkValue); - } - - // we resolved a first reference, but we need to make sure this isn't a reference also. - return resolveResValue(resValue); - } - - /** - * Returns the {@link ResourceValue} referenced by the value of <var>value</var>. - * <p/> - * This method ensures that it returns a {@link ResourceValue} 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 ResourceValue} object or <code>null</code> - */ - public ResourceValue resolveResValue(ResourceValue value) { - if (value == null) { - return null; - } - - // if the resource value is a style, we simply return it. - if (value instanceof StyleResourceValue) { - return value; - } - - // else attempt to find another ResourceValue referenced by this one. - ResourceValue 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 ResourceValue} 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 ResourceValue} or <code>null</code>. - */ - ResourceValue 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; - - // eliminate 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 ResourceValue} 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 ResourceValue findResValue(String resType, String resName, boolean frameworkOnly) { - // map of ResouceValue for the given type - Map<String, ResourceValue> typeMap; - - // if allowed, search in the project resources first. - if (frameworkOnly == false) { - typeMap = mProjectResources.get(resType); - if (typeMap != null) { - ResourceValue item = typeMap.get(resName); - if (item != null) { - return item; - } - } - } - - // now search in the framework resources. - typeMap = mFrameworkResources.get(resType); - if (typeMap != null) { - ResourceValue item = typeMap.get(resName); - if (item != null) { - return item; - } - - // if it was not found and the type is an id, it is possible that the ID was - // generated dynamically when compiling the framework resources. - // Look for it in the R map. - if (BridgeConstants.RES_ID.equals(resType)) { - if (Bridge.getResourceValue(resType, resName) != null) { - return new ResourceValue(resType, resName, true); - } - } - } - - // didn't find the resource anywhere. - // This is normal if the resource is an ID that is generated automatically. - // For other resources, we output a warning - if ("+id".equals(resType) == false && "+android:id".equals(resType) == false) { //$NON-NLS-1$ //$NON-NLS-2$ - Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE, - "Couldn't resolve resource @" + - (frameworkOnly ? "android:" : "") + resType + "/" + resName, - new ResourceValue(resType, resName, frameworkOnly)); - } - 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 ResourceValue 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 ResourceValue getProjectResource(String resourceType, String resourceName) { - return getResource(resourceType, resourceName, mProjectResources); - } - - ResourceValue getResource(String resourceType, String resourceName, - Map<String, Map<String, ResourceValue>> resourceRepository) { - Map<String, ResourceValue> typeMap = resourceRepository.get(resourceType); - if (typeMap != null) { - ResourceValue item = typeMap.get(resourceName); - if (item != null) { - item = resolveResValue(item); - return item; - } - } - - // didn't find the resource anywhere. - return null; - - } - - /** - * Returns the {@link ResourceValue} 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 ResourceValue} object or <code>null</code> - */ - public ResourceValue findItemInStyle(StyleResourceValue style, String itemName) { - ResourceValue item = style.findValue(itemName); - - // if we didn't find it, we look in the parent style (if applicable) - if (item == null && mStyleInheritanceMap != null) { - StyleResourceValue 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. * <p/> diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java index e95d295bb608..61f47ba7aa1e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java @@ -19,8 +19,8 @@ package com.android.layoutlib.bridge.android; 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.ide.common.resources.ResourceResolver; import com.android.layoutlib.bridge.Bridge; -import com.android.layoutlib.bridge.BridgeConstants; import org.kxml2.io.KXmlParser; import org.xmlpull.v1.XmlPullParser; @@ -155,14 +155,14 @@ public final class BridgeInflater extends LayoutInflater { String[] layoutInfo = Bridge.resolveResourceValue(resource); if (layoutInfo != null) { - value = bridgeContext.getFrameworkResource(BridgeConstants.RES_LAYOUT, - layoutInfo[0]); + value = bridgeContext.getResolver().getFrameworkResource( + ResourceResolver.RES_LAYOUT, layoutInfo[0]); } else { layoutInfo = mProjectCallback.resolveResourceValue(resource); if (layoutInfo != null) { - value = bridgeContext.getProjectResource(BridgeConstants.RES_LAYOUT, - layoutInfo[0]); + value = bridgeContext.getResolver().getProjectResource( + ResourceResolver.RES_LAYOUT, layoutInfo[0]); } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java index 23d81a2b7ba7..3af6a1b5b92a 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java @@ -104,7 +104,7 @@ public final class BridgeResources extends Resources { if (resourceInfo != null) { platformResFlag_out[0] = true; - return mContext.getFrameworkResource(resourceInfo[1], resourceInfo[0]); + return mContext.getResolver().getFrameworkResource(resourceInfo[1], resourceInfo[0]); } // didn't find a match in the framework? look in the project. @@ -113,7 +113,7 @@ public final class BridgeResources extends Resources { if (resourceInfo != null) { platformResFlag_out[0] = false; - return mContext.getProjectResource(resourceInfo[1], resourceInfo[0]); + return mContext.getResolver().getProjectResource(resourceInfo[1], resourceInfo[0]); } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java index 84bb4d1dd304..b166da552c44 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java @@ -19,6 +19,7 @@ package com.android.layoutlib.bridge.android; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.ResourceValue; import com.android.ide.common.rendering.api.StyleResourceValue; +import com.android.ide.common.resources.ResourceResolver; import com.android.internal.util.XmlUtils; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.BridgeConstants; @@ -633,11 +634,11 @@ 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.getFrameworkResourceValue(BridgeConstants.RES_ID, idName, defValue); + return mContext.getFrameworkResourceValue(ResourceResolver.RES_ID, idName, defValue); } // look for idName in the project R class. - return mContext.getProjectResourceValue(BridgeConstants.RES_ID, idName, defValue); + return mContext.getProjectResourceValue(ResourceResolver.RES_ID, idName, defValue); } // not a direct id valid reference? resolve it @@ -682,7 +683,7 @@ public final class BridgeTypedArray extends TypedArray { ResourceValue value = mResourceData[index]; String stringValue = value.getValue(); - if (stringValue == null || BridgeConstants.REFERENCE_NULL.equals(stringValue)) { + if (stringValue == null || ResourceResolver.REFERENCE_NULL.equals(stringValue)) { return null; } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java index 443d881e7a4d..8422d4890b0a 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java @@ -102,7 +102,7 @@ public final class BridgeWindowSession implements IWindowSession { } public void setInsets(IWindow window, int touchable, Rect contentInsets, - Rect visibleInsets) { + Rect visibleInsets, Region touchableRegion) { // pass for now. } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java index ba45217d708f..45d8e2647e5f 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java @@ -17,6 +17,7 @@ package com.android.layoutlib.bridge.android; import com.android.ide.common.rendering.api.ResourceValue; +import com.android.ide.common.resources.ResourceResolver; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.BridgeConstants; @@ -57,7 +58,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.getResourceValue(ResourceResolver.RES_ATTR, name); if (v != null) { return v.intValue(); } @@ -68,7 +69,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, + Integer v = mContext.getProjectCallback().getResourceValue(ResourceResolver.RES_ATTR, name); if (v != null) { return v.intValue(); @@ -102,8 +103,9 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes { private int resolveResourceValue(String value, int defaultValue) { // now look for this particular value - ResourceValue resource = mContext.resolveResValue( - mContext.findResValue(value, mPlatformFile)); + ResourceResolver resolver = mContext.getResolver(); + ResourceValue resource = resolver.resolveResValue( + resolver.findResValue(value, mPlatformFile)); if (resource != null) { Integer id = null; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 2439791f0097..a227d0c36d6c 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -38,9 +38,10 @@ import com.android.ide.common.rendering.api.StyleResourceValue; import com.android.ide.common.rendering.api.ViewInfo; import com.android.ide.common.rendering.api.Params.RenderingMode; import com.android.ide.common.rendering.api.Result.Status; +import com.android.ide.common.resources.ResourceResolver; +import com.android.ide.common.resources.ResourceResolver.IFrameworkResourceIdProvider; import com.android.internal.util.XmlUtils; import com.android.layoutlib.bridge.Bridge; -import com.android.layoutlib.bridge.BridgeConstants; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.BridgeInflater; import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes; @@ -73,8 +74,6 @@ import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -106,7 +105,6 @@ public class RenderSessionImpl { private BridgeContext mContext; private BridgeXmlBlockParser mBlockParser; private BridgeInflater mInflater; - private StyleResourceValue mCurrentTheme; private int mScreenOffset; private ResourceValue mWindowBackground; private FrameLayout mViewRoot; @@ -170,18 +168,23 @@ public class RenderSessionImpl { metrics.xdpi = mParams.getXdpi(); metrics.ydpi = mParams.getYdpi(); - // find the current theme and compute the style inheritance map - Map<StyleResourceValue, StyleResourceValue> styleParentMap = - new HashMap<StyleResourceValue, StyleResourceValue>(); + // create the resource resolver + ResourceResolver resolver = ResourceResolver.create( + new IFrameworkResourceIdProvider() { + public Integer getId(String resType, String resName) { + return Bridge.getResourceValue(resType, resName); + } + }, + mParams.getProjectResources(), + mParams.getFrameworkResources(), + mParams.getThemeName(), + mParams.isProjectTheme(), + mParams.getLog()); - mCurrentTheme = computeStyleMaps(mParams.getThemeName(), mParams.isProjectTheme(), - mParams.getProjectResources().get(BridgeConstants.RES_STYLE), - mParams.getFrameworkResources().get(BridgeConstants.RES_STYLE), styleParentMap); // build the context - mContext = new BridgeContext(mParams.getProjectKey(), metrics, mCurrentTheme, - mParams.getProjectResources(), mParams.getFrameworkResources(), - styleParentMap, mParams.getProjectCallback()); + mContext = new BridgeContext(mParams.getProjectKey(), metrics, resolver, + mParams.getProjectCallback()); // set the current rendering context sCurrentContext = mContext; @@ -193,12 +196,12 @@ public class RenderSessionImpl { // get the screen offset and window-background resource mWindowBackground = null; mScreenOffset = 0; - if (mCurrentTheme != null && mParams.isBgColorOverridden() == false) { - mWindowBackground = mContext.findItemInStyle(mCurrentTheme, "windowBackground"); - mWindowBackground = mContext.resolveResValue(mWindowBackground); + StyleResourceValue theme = resolver.getTheme(); + if (theme != null && mParams.isBgColorOverridden() == false) { + mWindowBackground = resolver.findItemInTheme("windowBackground"); + mWindowBackground = resolver.resolveResValue(mWindowBackground); - mScreenOffset = getScreenOffset(mParams.getFrameworkResources(), mCurrentTheme, - mContext); + mScreenOffset = getScreenOffset(resolver, metrics); } // build the inflater and parser. @@ -499,18 +502,18 @@ public class RenderSessionImpl { ResourceValue animationResource = null; int animationId = 0; if (isFrameworkAnimation) { - animationResource = mContext.getFrameworkResource(BridgeConstants.RES_ANIMATOR, - animationName); + animationResource = mContext.getResolver().getFrameworkResource( + ResourceResolver.RES_ANIMATOR, animationName); if (animationResource != null) { - animationId = Bridge.getResourceValue(BridgeConstants.RES_ANIMATOR, + animationId = Bridge.getResourceValue(ResourceResolver.RES_ANIMATOR, animationName); } } else { - animationResource = mContext.getProjectResource(BridgeConstants.RES_ANIMATOR, - animationName); + animationResource = mContext.getResolver().getProjectResource( + ResourceResolver.RES_ANIMATOR, animationName); if (animationResource != null) { animationId = mContext.getProjectCallback().getResourceValue( - BridgeConstants.RES_ANIMATOR, animationName); + ResourceResolver.RES_ANIMATOR, animationName); } } @@ -905,182 +908,21 @@ public class RenderSessionImpl { } } - - /** - * Compute style information from the given list of style for the project and framework. - * @param themeName the name of the current theme. In order to differentiate project and - * platform themes sharing the same name, all project themes must be prepended with - * a '*' character. - * @param isProjectTheme Is this a project theme - * @param inProjectStyleMap the project style map - * @param inFrameworkStyleMap the framework style map - * @param outInheritanceMap the map of style inheritance. This is filled by the method - * @return the {@link StyleResourceValue} matching <var>themeName</var> - */ - private StyleResourceValue computeStyleMaps( - String themeName, boolean isProjectTheme, Map<String, - ResourceValue> inProjectStyleMap, Map<String, ResourceValue> inFrameworkStyleMap, - Map<StyleResourceValue, StyleResourceValue> outInheritanceMap) { - - if (inProjectStyleMap != null && inFrameworkStyleMap != null) { - // first, get the theme - ResourceValue theme = null; - - // project theme names have been prepended with a * - if (isProjectTheme) { - theme = inProjectStyleMap.get(themeName); - } else { - theme = inFrameworkStyleMap.get(themeName); - } - - if (theme instanceof StyleResourceValue) { - // compute the inheritance map for both the project and framework styles - computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap, - inFrameworkStyleMap, outInheritanceMap); - - // Compute the style inheritance for the framework styles/themes. - // Since, for those, the style parent values do not contain 'android:' - // we want to force looking in the framework style only to avoid using - // similarly named styles from the project. - // To do this, we pass null in lieu of the project style map. - computeStyleInheritance(inFrameworkStyleMap.values(), null /*inProjectStyleMap */, - inFrameworkStyleMap, outInheritanceMap); - - return (StyleResourceValue)theme; - } - } - - return null; - } - - /** - * Compute the parent style for all the styles in a given list. - * @param styles the styles for which we compute the parent. - * @param inProjectStyleMap the map of project styles. - * @param inFrameworkStyleMap the map of framework styles. - * @param outInheritanceMap the map of style inheritance. This is filled by the method. - */ - private void computeStyleInheritance(Collection<ResourceValue> styles, - Map<String, ResourceValue> inProjectStyleMap, - Map<String, ResourceValue> inFrameworkStyleMap, - Map<StyleResourceValue, StyleResourceValue> outInheritanceMap) { - for (ResourceValue value : styles) { - if (value instanceof StyleResourceValue) { - StyleResourceValue style = (StyleResourceValue)value; - StyleResourceValue parentStyle = null; - - // first look for a specified parent. - String parentName = style.getParentStyle(); - - // no specified parent? try to infer it from the name of the style. - if (parentName == null) { - parentName = getParentName(value.getName()); - } - - if (parentName != null) { - parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap); - - if (parentStyle != null) { - outInheritanceMap.put(style, parentStyle); - } - } - } - } - } - - /** - * Searches for and returns the {@link StyleResourceValue} from a given name. - * <p/>The format of the name can be: - * <ul> - * <li>[android:]<name></li> - * <li>[android:]style/<name></li> - * <li>@[android:]style/<name></li> - * </ul> - * @param parentName the name of the style. - * @param inProjectStyleMap the project style map. Can be <code>null</code> - * @param inFrameworkStyleMap the framework style map. - * @return The matching {@link StyleResourceValue} object or <code>null</code> if not found. - */ - private StyleResourceValue getStyle(String parentName, - Map<String, ResourceValue> inProjectStyleMap, - Map<String, ResourceValue> inFrameworkStyleMap) { - boolean frameworkOnly = false; - - String name = parentName; - - // remove the useless @ if it's there - if (name.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) { - name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length()); - } - - // check for framework identifier. - if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) { - frameworkOnly = true; - name = name.substring(BridgeConstants.PREFIX_ANDROID.length()); - } - - // at this point we could have the format <type>/<name>. we want only the name as long as - // the type is style. - if (name.startsWith(BridgeConstants.REFERENCE_STYLE)) { - name = name.substring(BridgeConstants.REFERENCE_STYLE.length()); - } else if (name.indexOf('/') != -1) { - return null; - } - - ResourceValue parent = null; - - // if allowed, search in the project resources. - if (frameworkOnly == false && inProjectStyleMap != null) { - parent = inProjectStyleMap.get(name); - } - - // if not found, then look in the framework resources. - if (parent == null) { - parent = inFrameworkStyleMap.get(name); - } - - // make sure the result is the proper class type and return it. - if (parent instanceof StyleResourceValue) { - return (StyleResourceValue)parent; - } - - assert false; - mParams.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE, - String.format("Unable to resolve parent style name: %s", parentName), - null /*data*/); - - return null; - } - - /** - * Computes the name of the parent style, or <code>null</code> if the style is a root style. - */ - private String getParentName(String styleName) { - int index = styleName.lastIndexOf('.'); - if (index != -1) { - return styleName.substring(0, index); - } - - return null; - } - /** * Returns the top screen offset. This depends on whether the current theme defines the user * of the title and status bars. - * @param frameworkResources The framework resources - * @param currentTheme The current theme - * @param context The context + * @param resolver The {@link ResourceResolver} + * @param metrics The display metrics * @return the pixel height offset */ - private int getScreenOffset(Map<String, Map<String, ResourceValue>> frameworkResources, - StyleResourceValue currentTheme, BridgeContext context) { + private int getScreenOffset(ResourceResolver resolver, DisplayMetrics metrics) { int offset = 0; // get the title bar flag from the current theme. - ResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle"); + ResourceValue value = resolver.findItemInTheme("windowNoTitle"); // because it may reference something else, we resolve it. - value = context.resolveResValue(value); + value = resolver.resolveResValue(value); // if there's a value and it's true (default is false) if (value == null || value.getValue() == null || @@ -1089,17 +931,17 @@ public class RenderSessionImpl { int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT; // get value from the theme. - value = context.findItemInStyle(currentTheme, "windowTitleSize"); + value = resolver.findItemInTheme("windowTitleSize"); // resolve it - value = context.resolveResValue(value); + value = resolver.resolveResValue(value); if (value != null) { // get the numerical value, if available TypedValue typedValue = ResourceHelper.getValue(value.getValue()); if (typedValue != null) { // compute the pixel value based on the display metrics - defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics); + defaultOffset = (int)typedValue.getDimension(metrics); } } @@ -1107,10 +949,10 @@ public class RenderSessionImpl { } // get the fullscreen flag from the current theme. - value = context.findItemInStyle(currentTheme, "windowFullscreen"); + value = resolver.findItemInTheme("windowFullscreen"); // because it may reference something else, we resolve it. - value = context.resolveResValue(value); + value = resolver.resolveResValue(value); if (value == null || value.getValue() == null || XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) { @@ -1118,16 +960,13 @@ public class RenderSessionImpl { // default value int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT; - // get the real value, first the list of Dimensions from the framework map - Map<String, ResourceValue> dimens = frameworkResources.get(BridgeConstants.RES_DIMEN); - - // now get the value - value = dimens.get("status_bar_height"); + // get the real value + value = resolver.getFrameworkResource(ResourceResolver.RES_DIMEN, "status_bar_height"); if (value != null) { TypedValue typedValue = ResourceHelper.getValue(value.getValue()); if (typedValue != null) { // compute the pixel value based on the display metrics - defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics); + defaultOffset = (int)typedValue.getDimension(metrics); } } @@ -1136,7 +975,6 @@ public class RenderSessionImpl { } return offset; - } /** |