Merge "Adding framework support for resizable widgets"
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 751a8d3..f98d275 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -1077,6 +1077,8 @@
}
public synchronized boolean removeBondInternal(String address) {
+ // Unset the trusted device state and then unpair
+ setTrust(address, false);
return removeDeviceNative(getObjectPathFromAddress(address));
}
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 13a911b..2d2165b 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -20,7 +20,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
-import java.util.Map;
import android.appwidget.AppWidgetManager;
import android.content.Context;
@@ -33,8 +32,8 @@
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
import com.android.internal.widget.IRemoteViewsAdapterConnection;
import com.android.internal.widget.IRemoteViewsFactory;
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index fb2c416..e0b08d4 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -21,8 +21,6 @@
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
-import android.util.Log;
-import android.util.Pair;
import com.android.internal.widget.IRemoteViewsFactory;
@@ -40,9 +38,9 @@
// reclaimed), the references to the factories that are created need to be stored and used when
// the service is restarted (in response to user input for example). When the process is
// destroyed, so is this static cache of RemoteViewsFactories.
- private static final HashMap<Intent.FilterComparison, RemoteViewsFactory> mRemoteViewFactories =
+ private static final HashMap<Intent.FilterComparison, RemoteViewsFactory> sRemoteViewFactories =
new HashMap<Intent.FilterComparison, RemoteViewsFactory>();
- private final Object mLock = new Object();
+ private static final Object sLock = new Object();
/**
* An interface for an adapter between a remote collection view (ListView, GridView, etc) and
@@ -162,6 +160,16 @@
public synchronized boolean hasStableIds() {
return mFactory.hasStableIds();
}
+ public void onDestroy(Intent intent) {
+ synchronized (sLock) {
+ Intent.FilterComparison fc = new Intent.FilterComparison(intent);
+ if (RemoteViewsService.sRemoteViewFactories.containsKey(fc)) {
+ RemoteViewsFactory factory = RemoteViewsService.sRemoteViewFactories.get(fc);
+ factory.onDestroy();
+ RemoteViewsService.sRemoteViewFactories.remove(fc);
+ }
+ }
+ }
private RemoteViewsFactory mFactory;
private boolean mIsCreated;
@@ -169,17 +177,17 @@
@Override
public IBinder onBind(Intent intent) {
- synchronized (mLock) {
+ synchronized (sLock) {
Intent.FilterComparison fc = new Intent.FilterComparison(intent);
RemoteViewsFactory factory = null;
boolean isCreated = false;
- if (!mRemoteViewFactories.containsKey(fc)) {
+ if (!sRemoteViewFactories.containsKey(fc)) {
factory = onGetViewFactory(intent);
- mRemoteViewFactories.put(fc, factory);
+ sRemoteViewFactories.put(fc, factory);
factory.onCreate();
isCreated = false;
} else {
- factory = mRemoteViewFactories.get(fc);
+ factory = sRemoteViewFactories.get(fc);
isCreated = true;
}
return new RemoteViewsFactoryAdapter(factory, isCreated);
diff --git a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
index 60eca00..5857acb 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
@@ -16,11 +16,13 @@
package com.android.internal.widget;
+import android.content.Intent;
import android.widget.RemoteViews;
/** {@hide} */
interface IRemoteViewsFactory {
void onDataSetChanged();
+ void onDestroy(in Intent intent);
int getCount();
RemoteViews getViewAt(int position);
RemoteViews getLoadingView();
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index bd5305d..7a53874 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -31,8 +31,6 @@
#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
-#include <utils/List.h>
-#include <utils/KeyedVector.h>
#include <cutils/logger.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
@@ -324,15 +322,25 @@
class JavaBBinderHolder : public RefBase
{
public:
- sp<JavaBBinder> get(JNIEnv* env, jobject obj)
+ JavaBBinderHolder(JNIEnv* env, jobject object)
+ : mObject(object)
+ {
+ LOGV("Creating JavaBBinderHolder for Object %p\n", object);
+ }
+ ~JavaBBinderHolder()
+ {
+ LOGV("Destroying JavaBBinderHolder for Object %p\n", mObject);
+ }
+
+ sp<JavaBBinder> get(JNIEnv* env)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
- b = new JavaBBinder(env, obj);
+ b = new JavaBBinder(env, mObject);
mBinder = b;
LOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%d\n",
- b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
+ b.get(), b->getWeakRefs(), mObject, b->getWeakRefs()->getWeakCount());
}
return b;
@@ -346,41 +354,20 @@
private:
Mutex mLock;
+ jobject mObject;
wp<JavaBBinder> mBinder;
};
// ----------------------------------------------------------------------------
-// Per-IBinder death recipient bookkeeping. This is how we reconcile local jobject
-// death recipient references passed in through JNI with the permanent corresponding
-// JavaDeathRecipient objects.
-
-class JavaDeathRecipient;
-
-class DeathRecipientList : public RefBase {
- List< sp<JavaDeathRecipient> > mList;
- Mutex mLock;
-
-public:
- ~DeathRecipientList();
-
- void add(const sp<JavaDeathRecipient>& recipient);
- void remove(const sp<JavaDeathRecipient>& recipient);
- sp<JavaDeathRecipient> find(jobject recipient);
-};
-
-// ----------------------------------------------------------------------------
-
class JavaDeathRecipient : public IBinder::DeathRecipient
{
public:
- JavaDeathRecipient(JNIEnv* env, jobject object, sp<DeathRecipientList>& list)
- : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)), mList(list)
+ JavaDeathRecipient(JNIEnv* env, jobject object)
+ : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
+ mHoldsRef(true)
{
- // These objects manage their own lifetimes so are responsible for final bookkeeping.
- // The list holds a strong reference to this object.
- mList->add(this);
-
+ incStrong(this);
android_atomic_inc(&gNumDeathRefs);
incRefsCreated(env);
}
@@ -404,12 +391,16 @@
void clearReference()
{
- mList->remove(this);
- }
-
- bool matches(jobject obj) {
- JNIEnv* env = javavm_to_jnienv(mVM);
- return env->IsSameObject(obj, mObject);
+ bool release = false;
+ mLock.lock();
+ if (mHoldsRef) {
+ mHoldsRef = false;
+ release = true;
+ }
+ mLock.unlock();
+ if (release) {
+ decStrong(this);
+ }
}
protected:
@@ -424,57 +415,12 @@
private:
JavaVM* const mVM;
jobject const mObject;
- sp<DeathRecipientList> mList;
+ Mutex mLock;
+ bool mHoldsRef;
};
// ----------------------------------------------------------------------------
-DeathRecipientList::~DeathRecipientList() {
- AutoMutex _l(mLock);
-
- // Should never happen -- the JavaDeathRecipient objects that have added themselves
- // to the list are holding references on the list object. Only when they are torn
- // down can the list header be destroyed.
- if (mList.size() > 0) {
- LOGE("Retiring binder %p with extant death recipients\n", this);
- }
-}
-
-void DeathRecipientList::add(const sp<JavaDeathRecipient>& recipient) {
- AutoMutex _l(mLock);
-
- mList.push_back(recipient);
-}
-
-void DeathRecipientList::remove(const sp<JavaDeathRecipient>& recipient) {
- AutoMutex _l(mLock);
-
- List< sp<JavaDeathRecipient> >::iterator iter;
- for (iter = mList.begin(); iter != mList.end(); iter++) {
- if (*iter == recipient) {
- mList.erase(iter);
- return;
- }
- }
-}
-
-sp<JavaDeathRecipient> DeathRecipientList::find(jobject recipient) {
- AutoMutex _l(mLock);
-
- List< sp<JavaDeathRecipient> >::iterator iter;
- for (iter = mList.begin(); iter != mList.end(); iter++) {
- if ((*iter)->matches(recipient)) {
- return *iter;
- }
- }
- return NULL;
-}
-
-static KeyedVector<IBinder*, sp<DeathRecipientList> > gDeathRecipientsByIBinder;
-static Mutex gDeathRecipientMapLock;
-
-// ----------------------------------------------------------------------------
-
namespace android {
static void proxy_cleanup(const void* id, void* obj, void* cleanupCookie)
@@ -544,7 +490,7 @@
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetIntField(obj, gBinderOffsets.mObject);
- return jbh != NULL ? jbh->get(env, obj) : NULL;
+ return jbh != NULL ? jbh->get(env) : NULL;
}
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
@@ -675,26 +621,26 @@
IPCThreadState::self()->flushCommands();
}
-static void android_os_Binder_init(JNIEnv* env, jobject obj)
+static void android_os_Binder_init(JNIEnv* env, jobject clazz)
{
- JavaBBinderHolder* jbh = new JavaBBinderHolder();
+ JavaBBinderHolder* jbh = new JavaBBinderHolder(env, clazz);
if (jbh == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return;
}
- LOGV("Java Binder %p: acquiring first ref on holder %p", obj, jbh);
- jbh->incStrong((void*)android_os_Binder_init);
- env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
+ LOGV("Java Binder %p: acquiring first ref on holder %p", clazz, jbh);
+ jbh->incStrong(clazz);
+ env->SetIntField(clazz, gBinderOffsets.mObject, (int)jbh);
}
-static void android_os_Binder_destroy(JNIEnv* env, jobject obj)
+static void android_os_Binder_destroy(JNIEnv* env, jobject clazz)
{
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
- env->GetIntField(obj, gBinderOffsets.mObject);
+ env->GetIntField(clazz, gBinderOffsets.mObject);
if (jbh != NULL) {
- env->SetIntField(obj, gBinderOffsets.mObject, 0);
- LOGV("Java Binder %p: removing ref on holder %p", obj, jbh);
- jbh->decStrong((void*)android_os_Binder_init);
+ env->SetIntField(clazz, gBinderOffsets.mObject, 0);
+ LOGV("Java Binder %p: removing ref on holder %p", clazz, jbh);
+ jbh->decStrong(clazz);
} else {
// Encountering an uninitialized binder is harmless. All it means is that
// the Binder was only partially initialized when its finalizer ran and called
@@ -702,7 +648,7 @@
// For example, a Binder subclass constructor might have thrown an exception before
// it could delegate to its superclass's constructor. Consequently init() would
// not have been called and the holder pointer would remain NULL.
- LOGV("Java Binder %p: ignoring uninitialized binder", obj);
+ LOGV("Java Binder %p: ignoring uninitialized binder", clazz);
}
}
@@ -1027,25 +973,8 @@
LOGV("linkToDeath: binder=%p recipient=%p\n", target, recipient);
if (!target->localBinder()) {
- sp<JavaDeathRecipient> jdr;
-
- {
- sp<DeathRecipientList> list;
- AutoMutex _maplocker(gDeathRecipientMapLock);
-
- ssize_t listIndex = gDeathRecipientsByIBinder.indexOfKey(target);
- if (listIndex < 0) {
- // Set up the death notice bookkeeping for this binder lazily
- list = new DeathRecipientList;
- gDeathRecipientsByIBinder.add(target, list);
- } else {
- list = gDeathRecipientsByIBinder.valueAt(listIndex);
- }
-
- jdr = new JavaDeathRecipient(env, recipient, list);
- }
-
- status_t err = target->linkToDeath(jdr, NULL, flags);
+ sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient);
+ status_t err = target->linkToDeath(jdr, recipient, flags);
if (err != NO_ERROR) {
// Failure adding the death recipient, so clear its reference
// now.
@@ -1074,29 +1003,15 @@
LOGV("unlinkToDeath: binder=%p recipient=%p\n", target, recipient);
if (!target->localBinder()) {
- status_t err = NAME_NOT_FOUND;
- sp<JavaDeathRecipient> origJDR;
- {
- AutoMutex _maplocker(gDeathRecipientMapLock);
- ssize_t listIndex = gDeathRecipientsByIBinder.indexOfKey(target);
- if (listIndex >= 0) {
- sp<DeathRecipientList> list = gDeathRecipientsByIBinder.valueAt(listIndex);
- origJDR = list->find(recipient);
+ wp<IBinder::DeathRecipient> dr;
+ status_t err = target->unlinkToDeath(NULL, recipient, flags, &dr);
+ if (err == NO_ERROR && dr != NULL) {
+ sp<IBinder::DeathRecipient> sdr = dr.promote();
+ JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get());
+ if (jdr != NULL) {
+ jdr->clearReference();
}
}
- // If we found the matching recipient, proceed to unlink using that
- if (origJDR != NULL) {
- wp<IBinder::DeathRecipient> dr;
- err = target->unlinkToDeath(origJDR, NULL, flags, &dr);
- if (err == NO_ERROR && dr != NULL) {
- sp<IBinder::DeathRecipient> sdr = dr.promote();
- JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get());
- if (jdr != NULL) {
- jdr->clearReference();
- }
- }
- }
-
if (err == NO_ERROR || err == DEAD_OBJECT) {
res = JNI_TRUE;
} else {
@@ -1116,15 +1031,6 @@
env->SetIntField(obj, gBinderProxyOffsets.mObject, 0);
b->decStrong(obj);
IPCThreadState::self()->flushCommands();
-
- // tear down the death recipient bookkeeping
- {
- AutoMutex _maplocker(gDeathRecipientMapLock);
- ssize_t listIndex = gDeathRecipientsByIBinder.indexOfKey(b);
- if (listIndex >= 0) {
- gDeathRecipientsByIBinder.removeItemsAt((size_t)listIndex);
- }
- }
}
// ----------------------------------------------------------------------------
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h
index 81b56c2..749a977 100644
--- a/include/binder/IBinder.h
+++ b/include/binder/IBinder.h
@@ -98,7 +98,7 @@
* Register the @a recipient for a notification if this binder
* goes away. If this binder object unexpectedly goes away
* (typically because its hosting process has been killed),
- * then DeathRecipient::binderDied() will be called with a reference
+ * then DeathRecipient::binderDied() will be called with a referene
* to this.
*
* The @a cookie is optional -- if non-NULL, it should be a
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 8a5ab99..1c1bc98 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -20,6 +20,9 @@
#include "rsFont.h"
#include "rsProgramFragment.h"
#include <cutils/properties.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
#include FT_BITMAP_H
#include <GLES/gl.h>
@@ -208,7 +211,7 @@
}
}
- penX += (cachedGlyph->mAdvance.x >> 6);
+ penX += (cachedGlyph->mAdvanceX >> 6);
// If we were given a specific number of glyphs, decrement
if (numGlyphs > 0) {
@@ -238,7 +241,8 @@
return;
}
- glyph->mAdvance = mFace->glyph->advance;
+ glyph->mAdvanceX = mFace->glyph->advance.x;
+ glyph->mAdvanceY = mFace->glyph->advance.y;
glyph->mBitmapLeft = mFace->glyph->bitmap_left;
glyph->mBitmapTop = mFace->glyph->bitmap_top;
@@ -803,6 +807,22 @@
}
}
+bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
+ if ((uint32_t)bitmap->rows > mMaxHeight) {
+ return false;
+ }
+
+ if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
+ *retOriginX = mCurrentCol;
+ *retOriginY = mCurrentRow;
+ mCurrentCol += bitmap->width;
+ mDirty = true;
+ return true;
+ }
+
+ return false;
+}
+
namespace android {
namespace renderscript {
diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h
index 4820999..91a5da9 100644
--- a/libs/rs/rsFont.h
+++ b/libs/rs/rsFont.h
@@ -23,8 +23,9 @@
#include <utils/Vector.h>
#include <utils/KeyedVector.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
+struct FT_LibraryRec_;
+struct FT_FaceRec_;
+struct FT_Bitmap_;
// ---------------------------------------------------------------------------
namespace android {
@@ -105,11 +106,12 @@
float mBitmapMaxU;
float mBitmapMaxV;
// Minimize how much we call freetype
- FT_UInt mGlyphIndex;
- FT_Vector mAdvance;
+ int32_t mGlyphIndex;
+ int32_t mAdvanceX;
+ int32_t mAdvanceY;
// Values below contain a glyph's origin in the bitmap
- FT_Int mBitmapLeft;
- FT_Int mBitmapTop;
+ int32_t mBitmapLeft;
+ int32_t mBitmapTop;
};
String8 mFontName;
@@ -120,7 +122,7 @@
bool init(const char *name, float fontSize, uint32_t dpi, const void *data = NULL, uint32_t dataLen = 0);
virtual void preDestroy() const;
- FT_Face mFace;
+ FT_FaceRec_ *mFace;
bool mInitialized;
bool mHasKerning;
@@ -173,21 +175,7 @@
mCurrentCol(currentCol), mDirty(false) {
}
- bool fitBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
- if ((uint32_t)bitmap->rows > mMaxHeight) {
- return false;
- }
-
- if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
- *retOriginX = mCurrentCol;
- *retOriginY = mCurrentRow;
- mCurrentCol += bitmap->width;
- mDirty = true;
- return true;
- }
-
- return false;
- }
+ bool fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY);
};
Vector<CacheTextureLine*> mCacheLines;
@@ -211,8 +199,8 @@
float mWhiteThreshold;
// Free type library, we only need one copy
- FT_Library mLibrary;
- FT_Library getLib();
+ FT_LibraryRec_ *mLibrary;
+ FT_LibraryRec_ *getLib();
Vector<Font*> mActiveFonts;
// Render state for the font
@@ -229,7 +217,7 @@
return (uint8_t*)mTextTexture->getPtr();
}
- bool cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY);
+ bool cacheBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY);
const Type* getCacheTextureType() {
return mTextTexture->getType();
}
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 445a4e4..e12926b 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -26,6 +26,8 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include <bcc/bcc.h>
+
using namespace android;
using namespace android::renderscript;
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index e794feb..2c74b5b 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -21,7 +21,7 @@
#include "RenderScriptEnv.h"
-#include <bcc/bcc.h>
+struct BCCOpaqueScript;
// ---------------------------------------------------------------------------
namespace android {
@@ -50,7 +50,7 @@
Program_t mProgram;
- BCCScriptRef mBccScript;
+ BCCOpaqueScript *mBccScript;
const Allocation *ptrToAllocation(const void *) const;
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 550bb3d..afa8d69 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -22,7 +22,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -57,7 +56,6 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
-import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -69,11 +67,13 @@
import android.util.TypedValue;
import android.util.Xml;
import android.widget.RemoteViews;
+import android.widget.RemoteViewsService;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.widget.IRemoteViewsAdapterConnection;
+import com.android.internal.widget.IRemoteViewsFactory;
class AppWidgetService extends IAppWidgetService.Stub
{
@@ -153,9 +153,12 @@
}
}
- // Manages connections to RemoteViewsServices
+ // Manages active connections to RemoteViewsServices
private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection>
mBoundRemoteViewsServices = new HashMap<Pair<Integer,FilterComparison>,ServiceConnection>();
+ // Manages persistent references to RemoteViewsServices from different App Widgets
+ private final HashMap<FilterComparison, HashSet<Integer>>
+ mRemoteViewsServicesAppWidgets = new HashMap<FilterComparison, HashSet<Integer>>();
Context mContext;
Locale mLocale;
@@ -429,6 +432,7 @@
}
}
+ // Binds to a specific RemoteViewsService
public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
synchronized (mAppWidgetIds) {
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
@@ -452,8 +456,8 @@
// that first. (This does not allow multiple connections to the same service under
// the same key)
ServiceConnectionProxy conn = null;
- Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
- new FilterComparison(intent));
+ FilterComparison fc = new FilterComparison(intent);
+ Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc);
if (mBoundRemoteViewsServices.containsKey(key)) {
conn = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key);
conn.disconnect();
@@ -471,9 +475,15 @@
} finally {
Binder.restoreCallingIdentity(token);
}
+
+ // Add it to the mapping of RemoteViewsService to appWidgetIds so that we can determine
+ // when we can call back to the RemoteViewsService later to destroy associated
+ // factories.
+ incrementAppWidgetServiceRefCount(appWidgetId, fc);
}
}
+ // Unbinds from a specific RemoteViewsService
public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
synchronized (mAppWidgetIds) {
// Unbind from the RemoteViewsService (which will trigger a callback to the bound
@@ -500,6 +510,7 @@
}
}
+ // Unbinds from a RemoteViewsService when we delete an app widget
private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) {
int appWidgetId = id.appWidgetId;
// Unbind all connections to Services bound to this AppWidgetId
@@ -515,6 +526,71 @@
it.remove();
}
}
+
+ // Check if we need to destroy any services (if no other app widgets are
+ // referencing the same service)
+ decrementAppWidgetServiceRefCount(appWidgetId);
+ }
+
+ // Destroys the cached factory on the RemoteViewsService's side related to the specified intent
+ private void destroyRemoteViewsService(final Intent intent) {
+ final ServiceConnection conn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ final IRemoteViewsFactory cb =
+ IRemoteViewsFactory.Stub.asInterface(service);
+ try {
+ cb.onDestroy(intent);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ mContext.unbindService(this);
+ }
+ @Override
+ public void onServiceDisconnected(android.content.ComponentName name) {
+ // Do nothing
+ }
+ };
+
+ // Bind to the service and remove the static intent->factory mapping in the
+ // RemoteViewsService.
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Adds to the ref-count for a given RemoteViewsService intent
+ private void incrementAppWidgetServiceRefCount(int appWidgetId, FilterComparison fc) {
+ HashSet<Integer> appWidgetIds = null;
+ if (mRemoteViewsServicesAppWidgets.containsKey(fc)) {
+ appWidgetIds = mRemoteViewsServicesAppWidgets.get(fc);
+ } else {
+ appWidgetIds = new HashSet<Integer>();
+ mRemoteViewsServicesAppWidgets.put(fc, appWidgetIds);
+ }
+ appWidgetIds.add(appWidgetId);
+ }
+
+ // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
+ // the ref-count reaches zero.
+ private void decrementAppWidgetServiceRefCount(int appWidgetId) {
+ Iterator<FilterComparison> it =
+ mRemoteViewsServicesAppWidgets.keySet().iterator();
+ while (it.hasNext()) {
+ final FilterComparison key = it.next();
+ final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
+ if (ids.remove(appWidgetId)) {
+ // If we have removed the last app widget referencing this service, then we
+ // should destroy it and remove it from this set
+ if (ids.isEmpty()) {
+ destroyRemoteViewsService(key.getIntent());
+ it.remove();
+ }
+ }
+ }
}
public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 0fa97a3..c061a83 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -978,13 +978,11 @@
}
private void handleSetBackgroundData(boolean enabled) {
- if (enabled != getBackgroundDataSetting()) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0);
- Intent broadcast = new Intent(
- ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
- mContext.sendBroadcast(broadcast);
- }
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0);
+ Intent broadcast = new Intent(
+ ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
+ mContext.sendBroadcast(broadcast);
}
/**
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 4decd1a..88fd678 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -1043,8 +1043,7 @@
@LayoutlibDelegate
/*package*/ static void native_drawText(int nativeCanvas, String text,
- int start, int end, float x,
- float y, int flags, int paint) {
+ int start, int end, float x, float y, int flags, int paint) {
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
@@ -1060,7 +1059,7 @@
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
- native_drawText(nativeCanvas, buffer, start, end, x, y, flags, paint);
+ native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint);
}
@LayoutlibDelegate