diff options
73 files changed, 1970 insertions, 1001 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 d14140902386..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" @@ -61561,6 +61562,36 @@ visibility="public" > </field> +<field name="externalCacheSize" + type="long" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="externalDataSize" + type="long" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="externalMediaSize" + type="long" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="packageName" type="java.lang.String" transient="false" @@ -95576,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" @@ -95607,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/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 1590bf42c2ca..5705057f25ee 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -1192,4 +1192,16 @@ public class ValueAnimator extends Animator { public static int getCurrentAnimationsCount() { return sAnimations.get().size(); } + + /** + * Clear all animations on this thread, without canceling or ending them. + * This should be used with caution. + * + * @hide + */ + public static void clearAllAnimations() { + sAnimations.get().clear(); + sPendingAnimations.get().clear(); + sDelayedAnims.get().clear(); + } } 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/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java index 9464321acbd1..28a288647885 100755 --- a/core/java/android/content/pm/PackageStats.java +++ b/core/java/android/content/pm/PackageStats.java @@ -19,20 +19,44 @@ package android.content.pm; import android.os.Parcel; import android.os.Parcelable; -import java.util.Arrays; - /** * implementation of PackageStats associated with a * application package. */ public class PackageStats implements Parcelable { + /** Name of the package to which this stats applies. */ public String packageName; + + /** Size of the code (e.g., APK) */ public long codeSize; + + /** + * Size of the internal data size for the application. (e.g., + * /data/data/<app>) + */ public long dataSize; + + /** Size of cache used by the application. (e.g., /data/data/<app>/cache) */ public long cacheSize; - + + /** + * Size of the external data used by the application (e.g., + * <sdcard>/Android/data/<app>) + */ + public long externalDataSize; + + /** + * Size of the external cache used by the application (i.e., on the SD + * card). If this is a subdirectory of the data directory, this size will be + * subtracted out of the external data size. + */ + public long externalCacheSize; + + /** Size of the external media size used by the application. */ + public long externalMediaSize; + public static final Parcelable.Creator<PackageStats> CREATOR - = new Parcelable.Creator<PackageStats>() { + = new Parcelable.Creator<PackageStats>() { public PackageStats createFromParcel(Parcel in) { return new PackageStats(in); } @@ -41,29 +65,49 @@ public class PackageStats implements Parcelable { return new PackageStats[size]; } }; - + public String toString() { - return "PackageStats{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + packageName + "}"; + final StringBuilder sb = new StringBuilder("PackageStats{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" packageName="); + sb.append(packageName); + sb.append(",codeSize="); + sb.append(codeSize); + sb.append(",dataSize="); + sb.append(dataSize); + sb.append(",cacheSize="); + sb.append(cacheSize); + sb.append(",externalDataSize="); + sb.append(externalDataSize); + sb.append(",externalCacheSize="); + sb.append(externalCacheSize); + sb.append(",externalMediaSize="); + sb.append(externalMediaSize); + return sb.toString(); } - + public PackageStats(String pkgName) { packageName = pkgName; } - + public PackageStats(Parcel source) { packageName = source.readString(); codeSize = source.readLong(); dataSize = source.readLong(); cacheSize = source.readLong(); + externalDataSize = source.readLong(); + externalCacheSize = source.readLong(); + externalMediaSize = source.readLong(); } - + public PackageStats(PackageStats pStats) { packageName = pStats.packageName; codeSize = pStats.codeSize; dataSize = pStats.dataSize; cacheSize = pStats.cacheSize; + externalDataSize = pStats.externalDataSize; + externalCacheSize = pStats.externalCacheSize; + externalMediaSize = pStats.externalMediaSize; } public int describeContents() { @@ -75,5 +119,8 @@ public class PackageStats implements Parcelable { dest.writeLong(codeSize); dest.writeLong(dataSize); dest.writeLong(cacheSize); + dest.writeLong(externalDataSize); + dest.writeLong(externalCacheSize); + dest.writeLong(externalMediaSize); } } 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 264af71eb438..2c100773951c 100644 --- a/core/java/android/widget/StackView.java +++ b/core/java/android/widget/StackView.java @@ -1,5 +1,4 @@ -/* - * Copyright (C) 2010 The Android Open Source Project +/* Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -209,22 +208,19 @@ 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); alphaOa.setDuration(FADE_IN_ANIMATION_DURATION); if (oldAlphaOa != null) oldAlphaOa.cancel(); alphaOa.start(); - view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation, + view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation, new WeakReference<ObjectAnimator>(alphaOa)); } else if (fromIndex == 0 && toIndex == 1) { // Slide item in @@ -270,7 +266,7 @@ public class StackView extends AdapterViewAnimator { alphaOa.setDuration(STACK_RELAYOUT_DURATION); if (oldAlphaOa != null) oldAlphaOa.cancel(); alphaOa.start(); - view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation, + view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation, new WeakReference<ObjectAnimator>(alphaOa)); } @@ -284,16 +280,20 @@ public class StackView extends AdapterViewAnimator { final float maxPerspectiveShiftY = mPerspectiveShiftY; final float maxPerspectiveShiftX = mPerspectiveShiftX; - index = mMaxNumActiveViews - index - 1; - if (index == mMaxNumActiveViews - 1) index--; + if (mStackMode == ITEMS_SLIDE_DOWN) { + index = mMaxNumActiveViews - index - 1; + if (index == mMaxNumActiveViews - 1) index--; + } else { + index--; + if (index < 0) index++; + } float r = (index * 1.0f) / (mMaxNumActiveViews - 2); final float scale = 1 - PERSPECTIVE_SCALE_FACTOR * (1 - r); - int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1; - float perspectiveTranslationY = -stackDirection * r * maxPerspectiveShiftY; - float scaleShiftCorrectionY = stackDirection * (1 - scale) * + float perspectiveTranslationY = r * maxPerspectiveShiftY; + float scaleShiftCorrectionY = (scale - 1) * (getMeasuredHeight() * (1 - PERSPECTIVE_SHIFT_FACTOR_Y) / 2.0f); final float transY = perspectiveTranslationY + scaleShiftCorrectionY; @@ -302,7 +302,7 @@ public class StackView extends AdapterViewAnimator { (getMeasuredWidth() * (1 - PERSPECTIVE_SHIFT_FACTOR_X) / 2.0f); final float transX = perspectiveTranslationX + scaleShiftCorrectionX; - // If this view is currently being animated for a certain position, we need to cancel + // If this view is currently being animated for a certain position, we need to cancel // this animation so as not to interfere with the new transformation. Object tag = view.getTag(com.android.internal.R.id.viewAnimation); if (tag instanceof WeakReference<?>) { @@ -515,11 +515,12 @@ public class StackView extends AdapterViewAnimator { private void beginGestureIfNeeded(float deltaY) { if ((int) Math.abs(deltaY) > mTouchSlop && mSwipeGestureType == GESTURE_NONE) { - int swipeGestureType = deltaY < 0 ? GESTURE_SLIDE_UP : GESTURE_SLIDE_DOWN; + final int swipeGestureType = deltaY < 0 ? GESTURE_SLIDE_UP : GESTURE_SLIDE_DOWN; cancelLongPress(); requestDisallowInterceptTouchEvent(true); if (mAdapter == null) return; + final int adapterCount = mAdapter.getCount(); int activeIndex; if (mStackMode == ITEMS_SLIDE_UP) { @@ -528,13 +529,20 @@ public class StackView extends AdapterViewAnimator { activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ? 1 : 0; } + boolean endOfStack = mLoopViews && adapterCount == 1 && + ((mStackMode == ITEMS_SLIDE_UP && swipeGestureType == GESTURE_SLIDE_UP) || + (mStackMode == ITEMS_SLIDE_DOWN && swipeGestureType == GESTURE_SLIDE_DOWN)); + boolean beginningOfStack = mLoopViews && adapterCount == 1 && + ((mStackMode == ITEMS_SLIDE_DOWN && swipeGestureType == GESTURE_SLIDE_UP) || + (mStackMode == ITEMS_SLIDE_UP && swipeGestureType == GESTURE_SLIDE_DOWN)); + int stackMode; - if (mLoopViews) { + if (mLoopViews && !beginningOfStack && !endOfStack) { stackMode = StackSlider.NORMAL_MODE; - } else if (mCurrentWindowStartUnbounded + activeIndex == -1) { + } else if (mCurrentWindowStartUnbounded + activeIndex == -1 || beginningOfStack) { activeIndex++; stackMode = StackSlider.BEGINNING_OF_STACK_MODE; - } else if (mCurrentWindowStartUnbounded + activeIndex == mAdapter.getCount() - 1) { + } else if (mCurrentWindowStartUnbounded + activeIndex == adapterCount - 1 || endOfStack) { stackMode = StackSlider.END_OF_STACK_MODE; } else { stackMode = StackSlider.NORMAL_MODE; @@ -989,6 +997,11 @@ public class StackView extends AdapterViewAnimator { @Override public void advance() { long timeSinceLastInteraction = System.currentTimeMillis() - mLastInteractionTime; + + if (mAdapter == null) return; + final int adapterCount = mAdapter.getCount(); + if (adapterCount == 1 && mLoopViews) return; + if (mSwipeGestureType == GESTURE_NONE && timeSinceLastInteraction > MIN_TIME_BETWEEN_INTERACTION_AND_AUTOADVANCE) { showNext(); @@ -1266,4 +1279,4 @@ public class StackView extends AdapterViewAnimator { mask.recycle(); } } -} +}
\ No newline at end of file diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java index 8e491e9fdd62..8825c02415e6 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuView.java +++ b/core/java/com/android/internal/view/menu/ActionMenuView.java @@ -20,7 +20,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; -import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; @@ -44,6 +43,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo private MenuBuilder mMenu; private int mMaxItems; + private int mWidthLimit; private boolean mReserveOverflow; private OverflowMenuButton mOverflowButton; private MenuPopupHelper mOverflowPopup; @@ -91,6 +91,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo final int screen = res.getConfiguration().screenLayout; mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE; + mWidthLimit = res.getDisplayMetrics().widthPixels / 2; TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme); mDivider = a.getDrawable(com.android.internal.R.styleable.Theme_dividerVertical); @@ -108,6 +109,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE; mMaxItems = getMaxActionButtons(); + mWidthLimit = getResources().getDisplayMetrics().widthPixels / 2; if (mMenu != null) { mMenu.setMaxActionItems(mMaxItems); updateChildren(false); @@ -172,6 +174,19 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo } public void initialize(MenuBuilder menu, int menuType) { + int width = mWidthLimit; + if (mReserveOverflow) { + if (mOverflowButton == null) { + OverflowMenuButton button = new OverflowMenuButton(mContext); + mOverflowButton = button; + } + final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + mOverflowButton.measure(spec, spec); + width -= mOverflowButton.getMeasuredWidth(); + } + + menu.setActionWidthLimit(width); + menu.setMaxActionItems(mMaxItems); mMenu = menu; updateChildren(true); @@ -219,9 +234,11 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo if (itemCount > 0) { addView(makeDividerView(), makeDividerLayoutParams()); } - OverflowMenuButton button = new OverflowMenuButton(mContext); - addView(button); - mOverflowButton = button; + if (mOverflowButton == null) { + OverflowMenuButton button = new OverflowMenuButton(mContext); + mOverflowButton = button; + } + addView(mOverflowButton); } else { mOverflowButton = null; } diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index 830c2c1f865a..588b10c2d066 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -27,9 +27,10 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Parcelable; -import android.util.Log; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.util.TypedValue; +import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextThemeWrapper; import android.view.KeyCharacterMap; import android.view.KeyEvent; @@ -38,8 +39,8 @@ import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; +import android.view.View.MeasureSpec; import android.view.ViewGroup; -import android.view.ContextMenu.ContextMenuInfo; import android.widget.AdapterView; import android.widget.BaseAdapter; @@ -164,6 +165,10 @@ public class MenuBuilder implements Menu { */ private int mMaxActionItems; /** + * The total width limit in pixels for all action items within a menu + */ + private int mActionWidthLimit; + /** * Whether or not the items (or any one item's action state) has changed since it was * last fetched. */ @@ -208,6 +213,11 @@ public class MenuBuilder implements Menu { private boolean mOptionalIconsVisible = false; + private ViewGroup mMeasureActionButtonParent; + + // Group IDs that have been added as actions - used temporarily, allocated here for reuse. + private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray(); + private static int getAlertDialogTheme(Context context) { TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme, @@ -1035,6 +1045,44 @@ public class MenuBuilder implements Menu { return mVisibleItems; } + /** + * @return A fake action button parent view for obtaining child views. + */ + private ViewGroup getMeasureActionButtonParent() { + if (mMeasureActionButtonParent == null) { + mMeasureActionButtonParent = (ViewGroup) mMenuTypes[TYPE_ACTION_BUTTON].getInflater() + .inflate(LAYOUT_RES_FOR_TYPE[TYPE_ACTION_BUTTON], null, false); + } + return mMeasureActionButtonParent; + } + + /** + * This method determines which menu items get to be 'action items' that will appear + * in an action bar and which items should be 'overflow items' in a secondary menu. + * The rules are as follows: + * + * <p>Items are considered for inclusion in the order specified within the menu. + * There is a limit of mMaxActionItems as a total count, optionally including the overflow + * menu button itself. This is a soft limit; if an item shares a group ID with an item + * previously included as an action item, the new item will stay with its group and become + * an action item itself even if it breaks the max item count limit. This is done to + * limit the conceptual complexity of the items presented within an action bar. Only a few + * unrelated concepts should be presented to the user in this space, and groups are treated + * as a single concept. + * + * <p>There is also a hard limit of consumed measurable space: mActionWidthLimit. This + * limit may be broken by a single item that exceeds the remaining space, but no further + * items may be added. If an item that is part of a group cannot fit within the remaining + * measured width, the entire group will be demoted to overflow. This is done to ensure room + * for navigation and other affordances in the action bar as well as reduce general UI clutter. + * + * <p>The space freed by demoting a full group cannot be consumed by future menu items. + * Once items begin to overflow, all future items become overflow items as well. This is + * to avoid inadvertent reordering that may break the app's intended design. + * + * @param reserveActionOverflow true if an overflow button should consume one space + * in the available item count + */ private void flagActionItems(boolean reserveActionOverflow) { if (reserveActionOverflow != mReserveActionOverflow) { mReserveActionOverflow = reserveActionOverflow; @@ -1048,9 +1096,13 @@ public class MenuBuilder implements Menu { final ArrayList<MenuItemImpl> visibleItems = getVisibleItems(); final int itemsSize = visibleItems.size(); int maxActions = mMaxActionItems; + int widthLimit = mActionWidthLimit; + final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + final ViewGroup parent = getMeasureActionButtonParent(); int requiredItems = 0; int requestedItems = 0; + int firstActionWidth = 0; boolean hasOverflow = false; for (int i = 0; i < itemsSize; i++) { MenuItemImpl item = visibleItems.get(i); @@ -1070,12 +1122,68 @@ public class MenuBuilder implements Menu { } maxActions -= requiredItems; + final SparseBooleanArray seenGroups = mActionButtonGroups; + seenGroups.clear(); + // Flag as many more requested items as will fit. for (int i = 0; i < itemsSize; i++) { MenuItemImpl item = visibleItems.get(i); - if (item.requestsActionButton()) { - item.setIsActionButton(maxActions > 0); + + if (item.requiresActionButton()) { + View v = item.getActionView(); + if (v == null) { + v = item.getItemView(TYPE_ACTION_BUTTON, parent); + } + v.measure(querySpec, querySpec); + final int measuredWidth = v.getMeasuredWidth(); + widthLimit -= measuredWidth; + if (firstActionWidth == 0) { + firstActionWidth = measuredWidth; + } + final int groupId = item.getGroupId(); + if (groupId != 0) { + seenGroups.put(groupId, true); + } + } else if (item.requestsActionButton()) { + // Items in a group with other items that already have an action slot + // can break the max actions rule, but not the width limit. + final int groupId = item.getGroupId(); + final boolean inGroup = seenGroups.get(groupId); + boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0; maxActions--; + + if (isAction) { + View v = item.getActionView(); + if (v == null) { + v = item.getItemView(TYPE_ACTION_BUTTON, parent); + } + v.measure(querySpec, querySpec); + final int measuredWidth = v.getMeasuredWidth(); + widthLimit -= measuredWidth; + if (firstActionWidth == 0) { + firstActionWidth = measuredWidth; + } + + // Did this push the entire first item past halfway? + if (widthLimit + firstActionWidth <= 0) { + isAction = false; + } + } + + if (isAction && groupId != 0) { + seenGroups.put(groupId, true); + } else if (inGroup) { + // We broke the width limit. Demote the whole group, they all overflow now. + seenGroups.put(groupId, false); + for (int j = 0; j < i; j++) { + MenuItemImpl areYouMyGroupie = visibleItems.get(j); + if (areYouMyGroupie.getGroupId() == groupId) { + areYouMyGroupie.setIsActionButton(false); + } + } + } + + item.setIsActionButton(isAction); } } @@ -1108,6 +1216,11 @@ public class MenuBuilder implements Menu { mIsActionItemsStale = true; } + void setActionWidthLimit(int widthLimit) { + mActionWidthLimit = widthLimit; + mIsActionItemsStale = true; + } + public void clearHeader() { mHeaderIcon = null; mHeaderTitle = null; 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/core/res/res/layout/dialog_custom_title_holo.xml b/core/res/res/layout/dialog_custom_title_holo.xml index 854873f02e7e..74b6070a458f 100644 --- a/core/res/res/layout/dialog_custom_title_holo.xml +++ b/core/res/res/layout/dialog_custom_title_holo.xml @@ -23,10 +23,19 @@ This is an custom layout for a dialog. android:fitsSystemWindows="true"> <FrameLayout android:id="@android:id/title_container" android:layout_width="match_parent" - android:layout_height="24dip" + android:layout_height="60dip" android:layout_weight="0" + android:gravity="center_vertical|left" style="?android:attr/windowTitleBackgroundStyle"> </FrameLayout> + <ImageView android:id="@+id/titleDivider" + android:layout_width="match_parent" + android:layout_height="4dip" + android:scaleType="fitXY" + android:gravity="fill_horizontal" + android:paddingLeft="16dip" + android:paddingRight="16dip" + android:src="@android:drawable/divider_strong_holo" /> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" @@ -34,10 +43,6 @@ This is an custom layout for a dialog. android:foreground="?android:attr/windowContentOverlay"> <FrameLayout android:id="@android:id/content" android:layout_width="match_parent" - android:layout_height="match_parent" - android:paddingTop="6dip" - android:paddingBottom="10dip" - android:paddingLeft="10dip" - android:paddingRight="10dip" /> + android:layout_height="match_parent" /> </FrameLayout> </LinearLayout> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 1183915003d3..c4e815e86ebc 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -2057,7 +2057,7 @@ <!-- Window title --> <style name="WindowTitleBackground.Holo"> - <item name="android:background">@android:drawable/title_bar</item> + <item name="android:background">@null</item> </style> <style name="WindowTitle.Holo"> 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/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index 0c85af8e34d1..2ec222651436 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -165,8 +165,13 @@ public class DefaultContainerService extends IntentService { } @Override - public long calculateDirectorySize(String directory) throws RemoteException { - return MeasurementUtils.measureDirectory(directory); + public long calculateDirectorySize(String path) throws RemoteException { + final File directory = new File(path); + if (directory.exists() && directory.isDirectory()) { + return MeasurementUtils.measureDirectory(path); + } else { + return 0L; + } } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 73b67231a4b5..dfe0262dd525 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -668,7 +668,8 @@ public class PhoneStatusBarPolicy { if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){ iconLevel = getEvdoLevel(); if (false) { - Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel()); + Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + + getCdmaLevel()); } } else { iconLevel = getCdmaLevel(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java index 1b2fcadcbeb9..0d2538d82f8b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java @@ -55,7 +55,6 @@ public class AirplaneModeController extends BroadcastReceiver } public void onCheckedChanged(CompoundButton view, boolean checked) { - Slog.d(TAG, "onCheckedChanged checked=" + checked + " mAirplaneMode=" + mAirplaneMode); if (checked != mAirplaneMode) { mAirplaneMode = checked; unsafe(checked); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index 3a7bd90d7326..e80e37d95763 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -47,7 +47,6 @@ public class KeyButtonView extends ImageView { int mRepeat; Runnable mCheckLongPress = new Runnable() { public void run() { - Slog.d("KeyButtonView", "longpress"); if (isPressed()) { mLongPressed = true; mRepeat++; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java index 561615929571..90c95685ecd9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java @@ -73,12 +73,10 @@ public class HeightReceiver extends BroadcastReceiver { private void setPlugged(boolean plugged) { final Resources res = mContext.getResources(); - Slog.d(TAG, "plugged=" + plugged); int height = -1; if (plugged) { final DisplayMetrics metrics = new DisplayMetrics(); mWindowManager.getDefaultDisplay().getMetrics(metrics); - Slog.d(TAG, "metrics=" + metrics); height = metrics.heightPixels - 720; } @@ -87,7 +85,8 @@ public class HeightReceiver extends BroadcastReceiver { if (height < minHeight) { height = minHeight; } - Slog.d(TAG, "using height=" + height + " old=" + mHeight); + Slog.i(TAG, "Resizing status bar plugged=" + plugged + " height=" + + height + " old=" + mHeight); mHeight = height; final int N = mListeners.size(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java index d4ba6930d61c..add67b156785 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java @@ -242,6 +242,7 @@ public class InputMethodsPanel extends LinearLayout implements StatusBarPanel, O // Turn on the selected radio button at startup private void updateRadioButtonsByImiAndSubtype( InputMethodInfo imi, InputMethodSubtype subtype) { + if (imi == null) return; if (DEBUG) { Log.d(TAG, "Update radio buttons by " + imi.getId() + ", " + subtype); } @@ -253,7 +254,7 @@ public class InputMethodsPanel extends LinearLayout implements StatusBarPanel, O return; } Pair<InputMethodInfo, InputMethodSubtype> imiAndSubtype = - mRadioViewAndImiMap.get(radioView); + mRadioViewAndImiMap.get(radioView); if (imiAndSubtype.first.getId().equals(imi.getId()) && (imiAndSubtype.second == null || imiAndSubtype.second.equals(subtype))) { subtypeRadioButton.setChecked(true); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java index a2f6e3abdf99..45a22b61904d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java @@ -269,7 +269,8 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, // fully closed, no animation necessary } else if (mVisible) { if (DEBUG) { - Slog.d(TAG, "panelHeight not zero but trying to open; scheduling an anim to open fully"); + Slog.d(TAG, "panelHeight not zero but trying to open; scheduling an anim" + + " to open fully"); } startAnimation(true); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java index 07af46665623..9ca83e6bff8c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java @@ -95,7 +95,6 @@ public class SettingsView extends LinearLayout implements View.OnClickListener { // Network // ---------------------------- private void onClickNetwork() { - Slog.d(TAG, "onClickNetwork"); getContext().startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); getStatusBarManager().collapse(); @@ -104,7 +103,6 @@ public class SettingsView extends LinearLayout implements View.OnClickListener { // Settings // ---------------------------- private void onClickSettings() { - Slog.d(TAG, "onClickSettings"); getContext().startActivity(new Intent(Settings.ACTION_SETTINGS) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); getStatusBarManager().collapse(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java index 2ebd067a2675..e864577b97c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java @@ -143,7 +143,6 @@ public class ShirtPocket extends ImageView { hideWindow(); return true; } else if (action == MotionEvent.ACTION_DOWN) { - Slog.d(TAG, "ACTION_DOWN"); final ClipData clip = mClipping; if (clip != null) { final Bitmap icon = clip.getIcon(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index d8e3053ff68f..825877a7451f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -596,7 +596,7 @@ public class TabletStatusBar extends StatusBar implements // TODO: immersive mode popups for tablet } else if (notification.notification.fullScreenIntent != null) { // not immersive & a full-screen alert should be shown - Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;" + Slog.w(TAG, "Notification has fullScreenIntent and activity is not immersive;" + " sending fullScreenIntent"); try { notification.notification.fullScreenIntent.send(); @@ -732,28 +732,28 @@ public class TabletStatusBar extends StatusBar implements // act accordingly if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) { boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0; - Slog.d(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes")); + Slog.i(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes")); showClock(show); } if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { boolean show = (state & StatusBarManager.DISABLE_SYSTEM_INFO) == 0; - Slog.d(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes")); + Slog.i(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes")); mNotificationTrigger.setVisibility(show ? View.VISIBLE : View.GONE); } if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { if ((state & StatusBarManager.DISABLE_EXPAND) != 0) { - Slog.d(TAG, "DISABLE_EXPAND: yes"); + Slog.i(TAG, "DISABLE_EXPAND: yes"); animateCollapse(); } } if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { - Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes"); + Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes"); // synchronize with current shadow state mNotificationIconArea.setVisibility(View.GONE); mTicker.halt(); } else { - Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no"); + Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no"); // synchronize with current shadow state mNotificationIconArea.setVisibility(View.VISIBLE); } @@ -764,11 +764,11 @@ public class TabletStatusBar extends StatusBar implements } if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) { if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) { - Slog.d(TAG, "DISABLE_NAVIGATION: yes"); + Slog.i(TAG, "DISABLE_NAVIGATION: yes"); mNavigationArea.setVisibility(View.GONE); mInputMethodSwitchButton.setScreenLocked(true); } else { - Slog.d(TAG, "DISABLE_NAVIGATION: no"); + Slog.i(TAG, "DISABLE_NAVIGATION: no"); mNavigationArea.setVisibility(View.VISIBLE); mInputMethodSwitchButton.setScreenLocked(false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java index 4ee985df1f8e..98f718baccee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java @@ -65,7 +65,9 @@ public class TabletStatusBarView extends FrameLayout { } } } - Slog.d(TabletStatusBar.TAG, "TabletStatusBarView not intercepting event"); + if (TabletStatusBar.DEBUG) { + Slog.d(TabletStatusBar.TAG, "TabletStatusBarView not intercepting event"); + } return super.onInterceptTouchEvent(ev); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java index fa732c322485..440d68081fd0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java @@ -111,7 +111,6 @@ public class TabletTicker public void remove(IBinder key, boolean advance) { if (mCurrentKey == key) { - Slog.d(TAG, "removed current"); // Showing now if (advance) { removeMessages(MSG_ADVANCE); @@ -121,7 +120,6 @@ public class TabletTicker // In the queue for (int i=0; i<QUEUE_LENGTH; i++) { if (mKeys[i] == key) { - Slog.d(TAG, "removed from queue: " + i); for (; i<QUEUE_LENGTH-1; i++) { mKeys[i] = mKeys[i+1]; mQueue[i] = mQueue[i+1]; 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/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index d6b7366ea168..68c1453b8d75 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -197,7 +197,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { /* Another feature is enabled and the user is trying to enable the custom title feature */ throw new AndroidRuntimeException("You cannot combine custom titles with other title features"); } - if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && (featureId != FEATURE_CUSTOM_TITLE)) { + if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && + (featureId != FEATURE_CUSTOM_TITLE) && (featureId != FEATURE_ACTION_MODE_OVERLAY)) { /* Custom title feature is enabled and the user is trying to enable another feature */ throw new AndroidRuntimeException("You cannot combine custom titles with other title features"); 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/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 2b98795f3776..7b4f24697226 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -2540,16 +2540,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub ArrayList<String>>> enabledImes, String imeId, String subtypeHashCode) { for (Pair<String, ArrayList<String>> enabledIme: enabledImes) { if (enabledIme.first.equals(imeId)) { - final ArrayList<String> enabledSubtypes = enabledIme.second; - if (enabledSubtypes.size() == 0) { - // If there are no enabled subtypes, applicable subtypes are enabled - // implicitly. + final ArrayList<String> explicitlyEnabledSubtypes = enabledIme.second; + if (explicitlyEnabledSubtypes.size() == 0) { + // If there are no explicitly enabled subtypes, applicable subtypes are + // enabled implicitly. InputMethodInfo ime = mMethodMap.get(imeId); // If IME is enabled and no subtypes are enabled, applicable subtypes // are enabled implicitly, so needs to treat them to be enabled. if (ime != null && ime.getSubtypes().size() > 0) { List<InputMethodSubtype> implicitlySelectedSubtypes = - getApplicableSubtypesLocked(mRes, ime.getSubtypes()); + getApplicableSubtypesLocked(mRes, ime.getSubtypes()); if (implicitlySelectedSubtypes != null) { final int N = implicitlySelectedSubtypes.size(); for (int i = 0; i < N; ++i) { @@ -2561,7 +2561,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } } else { - for (String s: enabledSubtypes) { + for (String s: explicitlyEnabledSubtypes) { if (s.equals(subtypeHashCode)) { // If both imeId and subtypeId are enabled, return subtypeId. return s; 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/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 1c3967d9e878..19667d4a1be6 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -4806,6 +4806,74 @@ class PackageManagerService extends IPackageManager.Stub { abstract void handleReturnCode(); } + class MeasureParams extends HandlerParams { + private final PackageStats mStats; + private boolean mSuccess; + + private final IPackageStatsObserver mObserver; + + public MeasureParams(PackageStats stats, boolean success, + IPackageStatsObserver observer) { + mObserver = observer; + mStats = stats; + mSuccess = success; + } + + @Override + void handleStartCopy() throws RemoteException { + final boolean mounted; + + if (Environment.isExternalStorageEmulated()) { + mounted = true; + } else { + final String status = Environment.getExternalStorageState(); + + mounted = status.equals(Environment.MEDIA_MOUNTED) + || status.equals(Environment.MEDIA_MOUNTED_READ_ONLY); + } + + if (mounted) { + final File externalCacheDir = Environment + .getExternalStorageAppCacheDirectory(mStats.packageName); + final long externalCacheSize = mContainerService + .calculateDirectorySize(externalCacheDir.getPath()); + mStats.externalCacheSize = externalCacheSize; + + final File externalDataDir = Environment + .getExternalStorageAppDataDirectory(mStats.packageName); + long externalDataSize = mContainerService.calculateDirectorySize(externalDataDir + .getPath()); + + if (externalCacheDir.getParentFile().equals(externalDataDir)) { + externalDataSize -= externalCacheSize; + } + mStats.externalDataSize = externalDataSize; + + final File externalMediaDir = Environment + .getExternalStorageAppMediaDirectory(mStats.packageName); + mStats.externalMediaSize = mContainerService + .calculateDirectorySize(externalCacheDir.getPath()); + } + } + + @Override + void handleReturnCode() { + if (mObserver != null) { + try { + mObserver.onGetStatsCompleted(mStats, mSuccess); + } catch (RemoteException e) { + Slog.i(TAG, "Observer no longer exists."); + } + } + } + + @Override + void handleServiceError() { + Slog.e(TAG, "Could not measure application " + mStats.packageName + + " external storage"); + } + } + class InstallParams extends HandlerParams { final IPackageInstallObserver observer; int flags; @@ -6619,18 +6687,16 @@ class PackageManagerService extends IPackageManager.Stub { mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); - PackageStats lStats = new PackageStats(packageName); - final boolean succeded; + PackageStats stats = new PackageStats(packageName); + + final boolean success; synchronized (mInstallLock) { - succeded = getPackageSizeInfoLI(packageName, lStats); + success = getPackageSizeInfoLI(packageName, stats); } - if(observer != null) { - try { - observer.onGetStatsCompleted(lStats, succeded); - } catch (RemoteException e) { - Log.i(TAG, "Observer no longer exists."); - } - } //end if observer + + Message msg = mHandler.obtainMessage(INIT_COPY); + msg.obj = new MeasureParams(stats, success, observer); + mHandler.sendMessage(msg); } //end run }); } 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/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 154b8224c34f..65ad9568b3d3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2132,6 +2132,9 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, sh = (!sh) ? hw_h : sh; const size_t size = sw * sh * 4; + LOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d", + sw, sh, minLayerZ, maxLayerZ); + // make sure to clear all GL error flags while ( glGetError() != GL_NO_ERROR ) ; @@ -2146,6 +2149,9 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + + LOGD("screenshot: FBO created, status=0x%x", status); + if (status == GL_FRAMEBUFFER_COMPLETE_OES) { // invert everything, b/c glReadPixel() below will invert the FB @@ -2161,6 +2167,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); + LOGD("screenshot: glClear() issued"); + const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { @@ -2171,6 +2179,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, } } + LOGD("screenshot: All layers rendered"); + // XXX: this is needed on tegra glScissor(0, 0, sw, sh); @@ -2185,6 +2195,10 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, new MemoryHeapBase(size, 0, "screen-capture") ); void* const ptr = base->getBase(); if (ptr) { + + LOGD("screenshot: about to call glReadPixels(0,0,%d,%d,...,%p)", + sw, sh, ptr); + // capture the screen with glReadPixels() glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr); if (glGetError() == GL_NO_ERROR) { @@ -2197,25 +2211,32 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, } else { result = NO_MEMORY; } + + LOGD("screenshot: glReadPixels() returned %s", strerror(result)); + } glEnable(GL_SCISSOR_TEST); glViewport(0, 0, hw_w, hw_h); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); - - } else { result = BAD_VALUE; } + LOGD("screenshot: about to release FBO resources"); + // release FBO resources glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); glDeleteRenderbuffersOES(1, &tname); glDeleteFramebuffersOES(1, &name); + LOGD("screenshot: about to call compositionComplete()"); + hw.compositionComplete(); + LOGD("screenshot: result = %s", strerror(result)); + return result; } 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; - } /** |