Merge change 23300 into eclair
* changes:
Add a synchronous stop method to TTS synth engine so that upon its destruction, if it was synthesing to a file, the latter can be deleted without still being written to. Clear the hashmap of SpeechItem to be stopped (mKillList) when the speech queue is empty.
diff --git a/Android.mk b/Android.mk
index d348a52..97f012c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -358,6 +358,8 @@
guide/samples/LunarLander "Lunar Lander" \
-samplecode $(sample_dir)/NotePad \
guide/samples/NotePad "Note Pad" \
+ -samplecode $(sample_dir)/SearchableDictionary \
+ guide/samples/SearchableDictionary "Searchable Dictionary" \
-samplecode $(sample_dir)/Snake \
guide/samples/Snake "Snake" \
-samplecode $(sample_dir)/SoftKeyboard \
diff --git a/api/current.xml b/api/current.xml
index 403a961..3e616a4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -27066,6 +27066,17 @@
visibility="public"
>
</method>
+<method name="isYieldAllowed"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="newAssertQuery"
return="android.content.ContentProviderOperation.Builder"
abstract="false"
@@ -27292,6 +27303,19 @@
<parameter name="values" type="android.content.ContentValues">
</parameter>
</method>
+<method name="withYieldAllowed"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="yieldAllowed" type="boolean">
+</parameter>
+</method>
</class>
<class name="ContentProviderResult"
extends="java.lang.Object"
@@ -35833,6 +35857,39 @@
<parameter name="cause" type="java.lang.Throwable">
</parameter>
</constructor>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="numSuccessfulYieldPoints" type="int">
+</parameter>
+</constructor>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="numSuccessfulYieldPoints" type="int">
+</parameter>
+</constructor>
+<method name="getNumSuccessfulYieldPoints"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
</class>
<class name="ReceiverCallNotAllowedException"
extends="android.util.AndroidRuntimeException"
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 7741668..4d1e254 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -16,6 +16,7 @@
package android.app;
+import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.app.IWallpaperManagerCallback;
import android.content.ComponentName;
@@ -36,7 +37,8 @@
/**
* Get the wallpaper.
*/
- ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb);
+ ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
+ out Bundle outParams);
/**
* Clear the wallpaper.
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index b365d00..7e6efec 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -251,7 +251,7 @@
*
* <p>Once an application is configured to provide search suggestions, those same suggestions can
* easily be made available to the system-wide Quick Search Box, providing faster access to its
- * content from on central prominent place. See
+ * content from one central prominent place. See
* <a href="#ExposingSearchSuggestionsToQuickSearchBox">Exposing Search Suggestions to Quick Search
* Box</a> for more details.
*
@@ -505,7 +505,7 @@
*
* <tr><th>{@link #SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING}</th>
* <td>This column is used to specify that a spinner should be shown in lieu of an icon2
- * while the shortcut of this suggestion is being refreshed.</td>
+ * while the shortcut of this suggestion is being refreshed in Quick Search Box.</td>
* <td align="center">No. Only applicable to sources included in Quick Search Box.</td>
* </tr>
*
@@ -585,39 +585,45 @@
* <a name="ExposingSearchSuggestionsToQuickSearchBox"></a>
* <h3>Exposing Search Suggestions to Quick Search Box</h3>
*
- * <p>Once your application is setup to provide search suggestions, making them available to the
+ * <p>Once your application is set up to provide search suggestions, making them available to the
* globally accessable Quick Search Box is as easy as setting android:includeInGlobalSearch to
* "true" in your searchable metadata file. Beyond that, here are some more details of how
* suggestions interact with Quick Search Box, and optional ways that you may customize suggestions
* for your application.
+ *
+ * <p><b>Important Note:</b> By default, your application will not be enabled as a suggestion
+ * provider (or "searchable item") in Quick Search Box. Once your app is installed, the user must
+ * enable it as a "searchable item" in the Search settings in order to receive your app's
+ * suggestions in Quick Search Box. You should consider how to message this to users of your app -
+ * perhaps with a note to the user the first time they launch the app about how to enable search
+ * suggestions. This gives your app a chance to be queried for suggestions as the user types into
+ * Quick Search Box, though exactly how or if your suggestions will be surfaced is decided by Quick
+ * Search Box.
*
* <p><b>Source Ranking:</b> Once your application's search results are made available to Quick
- * Search Box, how they surface to the user for a particular query will depend on how many
- * other apps have results for that query, and how often the user has clicked on your results
- * compared to the other apps'. The apps with the best track record within Quick Search
- * Box will get queried earlier and have a better chance of showing their results in the top few
- * slots. If there are more results than can be displayed to the user within a screen or two, the
- * results may spill into a "more results" section that groups the remaining results by
- * source. The newest apps with little usage information are given middle of the road positioning
- * until enough usage information is available to rank it as usual. The exact formula for ranking
- * the results is not set in stone, but suffice it is to say that providing quality results will
- * increase the likelihood that your app's suggestions are provided in a prominent position, and
- * apps that provide lower quality suggestions will be more likely to be pushed into the spillover
- * area.
+ * Search Box, how they surface to the user for a particular query will be determined as appropriate
+ * by Quick Search Box ranking. This may depend on how many other apps have results for that query,
+ * and how often the user has clicked on your results compared to the other apps - but there is no
+ * guarantee about how ranking will occur, or whether your app's suggestions will show at all for
+ * a given query. In general, you can expect that providing quality results will increase the
+ * likelihood that your app's suggestions are provided in a prominent position, and apps that
+ * provide lower quality suggestions will be more likely to be ranked lower and/or not displayed.
*
* <p><b>Search Settings:</b> Each app that is available to Quick Search Box has an entry in the
* system settings where the user can enable or disable the inclusion of its results. Below the
* name of the application, each application may provide a brief description of what kind of
* information will be made available via a search settings description string pointed to by the
- * android:searchSettingsDescription attribute in the searchable metadata.
+ * android:searchSettingsDescription attribute in the searchable metadata. Note that the
+ * user will need to visit this settings menu to enable search suggestions for your app before your
+ * app will have a chance to provide search suggestions to Quick Search Box - see the section
+ * called "Important Note" above.
*
- * <p><b>Shortcuts:</b> Suggestions that are clicked on by the user are automatically made into
- * shortcuts, or, copied so they can quickly be displayed to the user before querying any of
- * the sources. Thereafter, the shortcutted suggestion will be displayed for the query that yielded
- * the suggestion and for any prefixes of that query. When multiple shortcuts are made available
- * for a given query, they are ranked based on recency and the number of clicks they have received.
- * You can control how your suggestions are made into shortcuts, and whether they are refreshed,
- * using the {@link #SUGGEST_COLUMN_SHORTCUT_ID} column:
+ * <p><b>Shortcuts:</b> Suggestions that are clicked on by the user may be automatically made into
+ * shortcuts, which are suggestions that have been copied from your provider in order to be quickly
+ * displayed without the need to re-query the original sources. Shortcutted suggestions may be
+ * displayed for the query that yielded the suggestion and for any prefixes of that query. You can
+ * request how to have your app's suggestions made into shortcuts, and whether they should be
+ * refreshed, using the {@link #SUGGEST_COLUMN_SHORTCUT_ID} column:
* <ul><li>Suggestions that do not include a shortcut id column will be made into shortcuts and
* never refreshed. This makes sense for suggestions that refer to data that will never be changed
* or removed.</li>
@@ -635,6 +641,9 @@
* <li>Finally, to prevent a suggestion from being copied into a shortcut, you may provide a
* shortcut id with a value of {@link #SUGGEST_NEVER_MAKE_SHORTCUT}.</li></ul>
*
+ * Note that Quick Search Box will ultimately decide whether to shortcut your app's suggestions,
+ * considering these values as a strong request from your application.
+ *
* <a name="ActionKeys"></a>
* <h3>Action Keys</h3>
*
@@ -807,7 +816,12 @@
* and editing.</td>
* </tr>
* </tbody>
- * </table></td>
+ * </table>
+ * Note that the icon of your app will likely be shown alongside any badge you specify,
+ * to differentiate search in your app from Quick Search Box. The display of this icon
+ * is not under the app's control.
+ * </td>
+ *
* <td align="center">No</td>
* </tr>
*
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c5ca0a3..7669306 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -21,13 +21,18 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.ViewRoot;
@@ -51,7 +56,7 @@
static class Globals extends IWallpaperManagerCallback.Stub {
private IWallpaperManager mService;
- private Drawable mWallpaper;
+ private Bitmap mWallpaper;
Globals() {
IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
@@ -69,7 +74,7 @@
}
}
- public Drawable peekWallpaper(Context context) {
+ public Bitmap peekWallpaperBitmap(Context context) {
synchronized (this) {
if (mWallpaper != null) {
return mWallpaper;
@@ -79,18 +84,82 @@
}
}
- private Drawable getCurrentWallpaperLocked(Context context) {
+ private Bitmap getCurrentWallpaperLocked(Context context) {
try {
- ParcelFileDescriptor fd = mService.getWallpaper(this);
+ Bundle params = new Bundle();
+ ParcelFileDescriptor fd = mService.getWallpaper(this, params);
if (fd != null) {
- Bitmap bm = BitmapFactory.decodeFileDescriptor(
- fd.getFileDescriptor(), null, null);
- if (bm != null) {
- // For now clear the density until we figure out how
- // to deal with it for wallpapers.
- bm.setDensity(0);
- return new BitmapDrawable(context.getResources(), bm);
+ int width = params.getInt("width", 0);
+ int height = params.getInt("height", 0);
+
+ if (width <= 0 || height <= 0) {
+ // Degenerate case: no size requested, just load
+ // bitmap as-is.
+ Bitmap bm = BitmapFactory.decodeFileDescriptor(
+ fd.getFileDescriptor(), null, null);
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
+ if (bm != null) {
+ bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+ }
+ return bm;
}
+
+ // Load the bitmap with full color depth, to preserve
+ // quality for later processing.
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inDither = false;
+ options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ Bitmap bm = BitmapFactory.decodeFileDescriptor(
+ fd.getFileDescriptor(), null, options);
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
+ if (bm == null) {
+ return bm;
+ }
+ bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+
+ // This is the final bitmap we want to return.
+ Bitmap newbm = Bitmap.createBitmap(width, height,
+ bm.getConfig());
+ newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+ Canvas c = new Canvas(newbm);
+ c.setDensity(DisplayMetrics.DENSITY_DEVICE);
+ Rect targetRect = new Rect();
+ targetRect.left = targetRect.top = 0;
+ targetRect.right = bm.getWidth();
+ targetRect.bottom = bm.getHeight();
+
+ int deltaw = width - targetRect.right;
+ int deltah = height - targetRect.bottom;
+
+ if (deltaw > 0 || deltah > 0) {
+ // We need to scale up so it covers the entire
+ // area.
+ float scale = 1.0f;
+ if (deltaw > deltah) {
+ scale = width / (float)targetRect.right;
+ } else {
+ scale = height / (float)targetRect.bottom;
+ }
+ targetRect.right = (int)(targetRect.right*scale);
+ targetRect.bottom = (int)(targetRect.bottom*scale);
+ deltaw = width - targetRect.right;
+ deltah = height - targetRect.bottom;
+ }
+
+ targetRect.offset(deltaw/2, deltah/2);
+ Paint paint = new Paint();
+ paint.setFilterBitmap(true);
+ paint.setDither(true);
+ c.drawBitmap(bm, null, targetRect, paint);
+
+ bm.recycle();
+ return newbm;
}
} catch (RemoteException e) {
}
@@ -149,7 +218,8 @@
* null pointer if these is none.
*/
public Drawable peekDrawable() {
- return getGlobals().peekWallpaper(mContext);
+ Bitmap bm = getGlobals().peekWallpaperBitmap(mContext);
+ return bm != null ? new BitmapDrawable(mContext.getResources(), bm) : null;
}
/**
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index 1edcb0a..d17775e 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -111,7 +111,8 @@
if (mSyncThread != null
&& mSyncThread.mSyncContext.getISyncContext().asBinder()
== syncContext.asBinder()) {
- mSyncThread.interrupt();
+ // TODO: figure out why canceling causes a hang
+// mSyncThread.interrupt();
}
}
}
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index f5a4b75..238792b 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -44,6 +44,7 @@
private final Integer mExpectedCount;
private final ContentValues mValuesBackReferences;
private final Map<Integer, Integer> mSelectionArgsBackReferences;
+ private final boolean mYieldAllowed;
/**
* Creates a {@link ContentProviderOperation} by copying the contents of a
@@ -58,6 +59,7 @@
mExpectedCount = builder.mExpectedCount;
mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences;
mValuesBackReferences = builder.mValuesBackReferences;
+ mYieldAllowed = builder.mYieldAllowed;
}
private ContentProviderOperation(Parcel source) {
@@ -68,7 +70,6 @@
mSelectionArgs = source.readInt() != 0 ? source.readStringArray() : null;
mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
mValuesBackReferences = source.readInt() != 0
-
? ContentValues.CREATOR.createFromParcel(source)
: null;
mSelectionArgsBackReferences = source.readInt() != 0
@@ -80,6 +81,7 @@
mSelectionArgsBackReferences.put(source.readInt(), source.readInt());
}
}
+ mYieldAllowed = source.readInt() != 0;
}
public void writeToParcel(Parcel dest, int flags) {
@@ -125,6 +127,7 @@
} else {
dest.writeInt(0);
}
+ dest.writeInt(mYieldAllowed ? 1 : 0);
}
/**
@@ -167,6 +170,10 @@
return mUri;
}
+ public boolean isYieldAllowed() {
+ return mYieldAllowed;
+ }
+
/** @hide exposed for unit tests */
public int getType() {
return mType;
@@ -375,6 +382,7 @@
private Integer mExpectedCount;
private ContentValues mValuesBackReferences;
private Map<Integer, Integer> mSelectionArgsBackReferences;
+ private boolean mYieldAllowed;
/** Create a {@link Builder} of a given type. The uri must not be null. */
private Builder(int type, Uri uri) {
@@ -544,5 +552,10 @@
mExpectedCount = count;
return this;
}
+
+ public Builder withYieldAllowed(boolean yieldAllowed) {
+ mYieldAllowed = yieldAllowed;
+ return this;
+ }
}
}
diff --git a/core/java/android/content/OperationApplicationException.java b/core/java/android/content/OperationApplicationException.java
index d4101bf..2fc19bb 100644
--- a/core/java/android/content/OperationApplicationException.java
+++ b/core/java/android/content/OperationApplicationException.java
@@ -21,16 +21,34 @@
* constraints.
*/
public class OperationApplicationException extends Exception {
+ private final int mNumSuccessfulYieldPoints;
+
public OperationApplicationException() {
super();
+ mNumSuccessfulYieldPoints = 0;
}
public OperationApplicationException(String message) {
super(message);
+ mNumSuccessfulYieldPoints = 0;
}
public OperationApplicationException(String message, Throwable cause) {
super(message, cause);
+ mNumSuccessfulYieldPoints = 0;
}
public OperationApplicationException(Throwable cause) {
super(cause);
+ mNumSuccessfulYieldPoints = 0;
+ }
+ public OperationApplicationException(int numSuccessfulYieldPoints) {
+ super();
+ mNumSuccessfulYieldPoints = numSuccessfulYieldPoints;
+ }
+ public OperationApplicationException(String message, int numSuccessfulYieldPoints) {
+ super(message);
+ mNumSuccessfulYieldPoints = numSuccessfulYieldPoints;
+ }
+
+ public int getNumSuccessfulYieldPoints() {
+ return mNumSuccessfulYieldPoints;
}
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d4a4c11..e48f539 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -20,6 +20,7 @@
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
+import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -215,6 +216,12 @@
* <P>Type: INTEGER</P>
*/
public static final String HAS_PHONE_NUMBER = "has_phone_number";
+
+ /**
+ * An opaque value that contains hints on how to find the contact if
+ * its row id changed as a result of a sync or aggregation.
+ */
+ public static final String LOOKUP_KEY = "lookup";
}
/**
@@ -234,6 +241,54 @@
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contacts");
/**
+ * A content:// style URI for this table that should be used to create
+ * shortcuts or otherwise create long-term links to contacts. This URI
+ * should always be followed by a "/" and the contact's {@link #LOOKUP_KEY}.
+ * It can optionally also have a "/" and last known contact ID appended after
+ * that. This "complete" format is an important optimization and is highly recommended.
+ * <p>
+ * As long as the contact's row ID remains the same, this URI is
+ * equivalent to {@link #CONTENT_URI}. If the contact's row ID changes
+ * as a result of a sync or aggregation, this URI will look up the
+ * contact using indirect information (sync IDs or constituent raw
+ * contacts).
+ * <p>
+ * Lookup key should be appended unencoded - it is stored in the encoded
+ * form, ready for use in a URI.
+ */
+ public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI,
+ "lookup");
+
+ /**
+ * Computes a complete lookup URI (see {@link #CONTENT_LOOKUP_URI}).
+ * Pass either a basic content URI with a contact ID to obtain an
+ * equivalent lookup URI. Pass a possibly stale lookup URI to get a fresh
+ * lookup URI for the same contact.
+ * <p>
+ * Returns null if the contact cannot be found.
+ */
+ public static Uri getLookupUri(ContentResolver resolver, Uri contentUri) {
+ Cursor c = resolver.query(contentUri,
+ new String[]{Contacts.LOOKUP_KEY, Contacts._ID}, null, null, null);
+ if (c == null) {
+ return null;
+ }
+
+ try {
+ if (c.moveToFirst()) {
+ String lookupKey = c.getString(0);
+ long contactId = c.getLong(1);
+ return ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey),
+ contactId);
+ }
+ } finally {
+ c.close();
+ }
+ return null;
+ }
+
+ /**
* The content:// style URI for this table joined with useful data from
* {@link Data}.
*
@@ -1042,6 +1097,7 @@
public static final int TYPE_HOME = 1;
public static final int TYPE_WORK = 2;
public static final int TYPE_OTHER = 3;
+ public static final int TYPE_MOBILE = 4;
/**
* The display name for the email address
diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
index 9586e34..bbd9dde 100644
--- a/core/java/android/service/wallpaper/IWallpaperEngine.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
@@ -20,5 +20,7 @@
* @hide
*/
oneway interface IWallpaperEngine {
+ void setDesiredSize(int width, int height);
+ void setVisibility(boolean visible);
void destroy();
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 629e97e..2cdfc66 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -55,6 +55,7 @@
private static final int DO_ATTACH = 10;
private static final int DO_DETACH = 20;
+ private static final int DO_SET_DESIRED_SIZE = 30;
private static final int MSG_UPDATE_SURFACE = 10000;
private static final int MSG_VISIBILITY_CHANGED = 10010;
@@ -78,6 +79,8 @@
IBinder mWindowToken;
boolean mInitializing = true;
+ boolean mVisible;
+ boolean mDestroyed;
// Current window state.
boolean mCreated;
@@ -129,8 +132,15 @@
return mIsCreating;
}
+ @Override
+ public void setFixedSize(int width, int height) {
+ throw new UnsupportedOperationException(
+ "Wallpapers currently only support sizing from layout");
+ }
+
public void setKeepScreenOn(boolean screenOn) {
- // Ignore.
+ throw new UnsupportedOperationException(
+ "Wallpapers do not support keep screen on");
}
};
@@ -166,9 +176,13 @@
@Override
public void dispatchAppVisibility(boolean visible) {
- Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
- visible ? 1 : 0);
- mCaller.sendMessage(msg);
+ // We don't do this in preview mode; we'll let the preview
+ // activity tell us when to run.
+ if (!mIWallpaperEngine.mIsPreview) {
+ Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
+ visible ? 1 : 0);
+ mCaller.sendMessage(msg);
+ }
}
@Override
@@ -212,6 +226,15 @@
}
/**
+ * Return whether the wallpaper is currently visible to the user,
+ * this is the last value supplied to
+ * {@link #onVisibilityChanged(boolean)}.
+ */
+ public boolean isVisible() {
+ return mVisible;
+ }
+
+ /**
* Returns true if this engine is running in preview mode -- that is,
* it is being shown to the user before they select it as the actual
* wallpaper.
@@ -280,6 +303,13 @@
}
/**
+ * Called when an application has changed the desired virtual size of
+ * the wallpaper.
+ */
+ public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) {
+ }
+
+ /**
* Convenience for {@link SurfaceHolder.Callback#surfaceChanged
* SurfaceHolder.Callback.surfaceChanged()}.
*/
@@ -301,6 +331,10 @@
}
void updateSurface(boolean forceRelayout, boolean forceReport) {
+ if (mDestroyed) {
+ Log.w(TAG, "Ignoring updateSurface: destroyed");
+ }
+
int myWidth = mSurfaceHolder.getRequestedWidth();
if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.FILL_PARENT;
int myHeight = mSurfaceHolder.getRequestedHeight();
@@ -314,7 +348,7 @@
if (forceRelayout || creating || formatChanged || sizeChanged
|| typeChanged || flagsChanged) {
- if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+ if (DEBUG) Log.v(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged);
try {
@@ -343,6 +377,8 @@
if (!mCreated) {
mLayout.type = mIWallpaperEngine.mWindowType;
mLayout.gravity = Gravity.LEFT|Gravity.TOP;
+ mLayout.windowAnimations =
+ com.android.internal.R.style.Animation_Wallpaper;
mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
}
@@ -354,7 +390,7 @@
View.VISIBLE, false, mWinFrame, mContentInsets,
mVisibleInsets, mSurfaceHolder.mSurface);
- if (DEBUG) Log.i(TAG, "New surface: " + mSurfaceHolder.mSurface
+ if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
+ ", frame=" + mWinFrame);
int w = mWinFrame.width();
@@ -384,6 +420,8 @@
if (!mCreated) {
mIsCreating = true;
+ if (DEBUG) Log.v(TAG, "onSurfaceCreated("
+ + mSurfaceHolder + "): " + this);
onSurfaceCreated(mSurfaceHolder);
if (callbacks != null) {
for (SurfaceHolder.Callback c : callbacks) {
@@ -399,6 +437,10 @@
+ " formatChanged=" + formatChanged
+ " sizeChanged=" + sizeChanged, e);
}
+ if (DEBUG) Log.v(TAG, "onSurfaceChanged("
+ + mSurfaceHolder + ", " + mFormat
+ + ", " + mCurWidth + ", " + mCurHeight
+ + "): " + this);
onSurfaceChanged(mSurfaceHolder, mFormat,
mCurWidth, mCurHeight);
if (callbacks != null) {
@@ -425,26 +467,73 @@
void attach(IWallpaperEngineWrapper wrapper) {
if (DEBUG) Log.v(TAG, "attach: " + this + " wrapper=" + wrapper);
+ if (mDestroyed) {
+ return;
+ }
+
mIWallpaperEngine = wrapper;
mCaller = wrapper.mCaller;
mConnection = wrapper.mConnection;
mWindowToken = wrapper.mWindowToken;
- // XXX temp -- should run in size from layout (screen) mode.
- mSurfaceHolder.setFixedSize(mIWallpaperEngine.mReqWidth,
- mIWallpaperEngine.mReqHeight);
- //mSurfaceHolder.setSizeFromLayout();
+ mSurfaceHolder.setSizeFromLayout();
mInitializing = true;
mSession = ViewRoot.getWindowSession(getMainLooper());
mWindow.setSession(mSession);
+ if (DEBUG) Log.v(TAG, "onCreate(): " + this);
onCreate(mSurfaceHolder);
mInitializing = false;
updateSurface(false, false);
}
+ void doDesiredSizeChanged(int desiredWidth, int desiredHeight) {
+ if (!mDestroyed) {
+ if (DEBUG) Log.v(TAG, "onDesiredSizeChanged("
+ + desiredWidth + "," + desiredHeight + "): " + this);
+ onDesiredSizeChanged(desiredWidth, desiredHeight);
+ }
+ }
+
+ void doVisibilityChanged(boolean visible) {
+ if (!mDestroyed) {
+ mVisible = visible;
+ if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible
+ + "): " + this);
+ onVisibilityChanged(visible);
+ }
+ }
+
+ void doOffsetsChanged() {
+ if (mDestroyed) {
+ return;
+ }
+
+ float xOffset;
+ float yOffset;
+ synchronized (mLock) {
+ xOffset = mPendingXOffset;
+ yOffset = mPendingYOffset;
+ mOffsetMessageEnqueued = false;
+ }
+ if (DEBUG) Log.v(TAG, "Offsets change in " + this
+ + ": " + xOffset + "," + yOffset);
+ final int availw = mIWallpaperEngine.mReqWidth-mCurWidth;
+ final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0;
+ final int availh = mIWallpaperEngine.mReqHeight-mCurHeight;
+ final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
+ onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
+ }
+
void detach() {
- onDestroy();
+ mDestroyed = true;
+
+ if (mVisible) {
+ mVisible = false;
+ if (DEBUG) Log.v(TAG, "onVisibilityChanged(false): " + this);
+ onVisibilityChanged(false);
+ }
+
if (mDestroyReportNeeded) {
mDestroyReportNeeded = false;
SurfaceHolder.Callback callbacks[];
@@ -456,7 +545,14 @@
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder);
}
+ if (DEBUG) Log.v(TAG, "onSurfaceDestroyed("
+ + mSurfaceHolder + "): " + this);
+ onSurfaceDestroyed(mSurfaceHolder);
}
+
+ if (DEBUG) Log.v(TAG, "onDestroy(): " + this);
+ onDestroy();
+
if (mCreated) {
try {
mSession.remove(mWindow);
@@ -492,16 +588,21 @@
mReqWidth = reqWidth;
mReqHeight = reqHeight;
- try {
- conn.attachEngine(this);
- } catch (RemoteException e) {
- destroy();
- }
-
Message msg = mCaller.obtainMessage(DO_ATTACH);
mCaller.sendMessage(msg);
}
+ public void setDesiredSize(int width, int height) {
+ Message msg = mCaller.obtainMessageII(DO_SET_DESIRED_SIZE, width, height);
+ mCaller.sendMessage(msg);
+ }
+
+ public void setVisibility(boolean visible) {
+ Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
+ visible ? 1 : 0);
+ mCaller.sendMessage(msg);
+ }
+
public void destroy() {
Message msg = mCaller.obtainMessage(DO_DETACH);
mCaller.sendMessage(msg);
@@ -510,6 +611,12 @@
public void executeMessage(Message message) {
switch (message.what) {
case DO_ATTACH: {
+ try {
+ mConnection.attachEngine(this);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Wallpaper host disappeared", e);
+ return;
+ }
Engine engine = onCreateEngine();
mEngine = engine;
engine.attach(this);
@@ -519,29 +626,20 @@
mEngine.detach();
return;
}
+ case DO_SET_DESIRED_SIZE: {
+ mEngine.doDesiredSizeChanged(message.arg1, message.arg2);
+ return;
+ }
case MSG_UPDATE_SURFACE:
mEngine.updateSurface(true, false);
break;
case MSG_VISIBILITY_CHANGED:
if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
+ ": " + message.arg1);
- mEngine.onVisibilityChanged(message.arg1 != 0);
+ mEngine.doVisibilityChanged(message.arg1 != 0);
break;
case MSG_WALLPAPER_OFFSETS: {
- float xOffset;
- float yOffset;
- synchronized (mEngine.mLock) {
- xOffset = mEngine.mPendingXOffset;
- yOffset = mEngine.mPendingYOffset;
- mEngine.mOffsetMessageEnqueued = false;
- }
- if (DEBUG) Log.v(TAG, "Offsets change in " + mEngine
- + ": " + xOffset + "," + yOffset);
- final int availw = mReqWidth-mEngine.mCurWidth;
- final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0;
- final int availh = mReqHeight-mEngine.mCurHeight;
- final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
- mEngine.onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
+ mEngine.doOffsetsChanged();
} break;
case MSG_WINDOW_RESIZED: {
final boolean reportDraw = message.arg1 != 0;
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index c4eb31f..5357469 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -33,52 +33,50 @@
*/
public class ImageWallpaper extends WallpaperService {
WallpaperManager mWallpaperManager;
- ImageWallpaper.DrawableEngine mEngine;
- private WallpaperObserver mReceiver;
@Override
public void onCreate() {
super.onCreate();
mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
- IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
- mReceiver = new WallpaperObserver();
- registerReceiver(mReceiver, filter);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- unregisterReceiver(mReceiver);
}
public Engine onCreateEngine() {
- mEngine = new DrawableEngine();
- return mEngine;
- }
-
- class WallpaperObserver extends BroadcastReceiver {
- public void onReceive(Context context, Intent intent) {
- mEngine.updateWallpaper();
- mEngine.drawFrame();
- }
+ return new DrawableEngine();
}
class DrawableEngine extends Engine {
private final Object mLock = new Object();
private final Rect mBounds = new Rect();
+ private WallpaperObserver mReceiver;
Drawable mBackground;
float mXOffset;
float mYOffset;
+ class WallpaperObserver extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ updateWallpaper();
+ drawFrame();
+ }
+ }
+
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
+ IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
+ mReceiver = new WallpaperObserver();
+ registerReceiver(mReceiver, filter);
updateWallpaper();
surfaceHolder.setSizeFromLayout();
//setTouchEventsEnabled(true);
}
@Override
+ public void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mReceiver);
+ }
+
+ @Override
public void onVisibilityChanged(boolean visible) {
drawFrame();
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4f789dd..1ea5fa3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -898,7 +898,7 @@
<permission android:name="android.permission.BIND_WALLPAPER"
android:label="@string/permlab_bindWallpaper"
android:description="@string/permdesc_bindWallpaper"
- android:protectionLevel="signature" />
+ android:protectionLevel="signatureOrSystem" />
<!-- Allows low-level access to setting the orientation (actually
rotation) of the screen. Not for use by normal applications. -->
diff --git a/core/res/res/anim/wallpaper_activity_close_enter.xml b/core/res/res/anim/wallpaper_activity_close_enter.xml
index fc6e332..9e9bd80 100644
--- a/core/res/res/anim/wallpaper_activity_close_enter.xml
+++ b/core/res/res/anim/wallpaper_activity_close_enter.xml
@@ -27,4 +27,6 @@
android:duration="@android:integer/config_mediumAnimTime" />
<translate android:fromXDelta="-150%" android:toXDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/wallpaper_activity_close_exit.xml b/core/res/res/anim/wallpaper_activity_close_exit.xml
index edd00fd..badbbf0 100644
--- a/core/res/res/anim/wallpaper_activity_close_exit.xml
+++ b/core/res/res/anim/wallpaper_activity_close_exit.xml
@@ -26,4 +26,6 @@
android:duration="@android:integer/config_mediumAnimTime" />
<translate android:fromXDelta="0%" android:toXDelta="100%"
android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/wallpaper_activity_open_enter.xml b/core/res/res/anim/wallpaper_activity_open_enter.xml
index 5b44d97..e60bac2 100644
--- a/core/res/res/anim/wallpaper_activity_open_enter.xml
+++ b/core/res/res/anim/wallpaper_activity_open_enter.xml
@@ -26,4 +26,6 @@
android:duration="@android:integer/config_mediumAnimTime" />
<translate android:fromXDelta="100%" android:toXDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/wallpaper_activity_open_exit.xml b/core/res/res/anim/wallpaper_activity_open_exit.xml
index fa39bee..01abbb7 100644
--- a/core/res/res/anim/wallpaper_activity_open_exit.xml
+++ b/core/res/res/anim/wallpaper_activity_open_exit.xml
@@ -27,4 +27,6 @@
android:duration="@android:integer/config_mediumAnimTime" />
<translate android:fromXDelta="0" android:toXDelta="-150%"
android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/wallpaper_enter.xml b/core/res/res/anim/wallpaper_enter.xml
new file mode 100644
index 0000000..981f5f6
--- /dev/null
+++ b/core/res/res/anim/wallpaper_enter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator">
+ <scale android:fromXScale="3.0" android:toXScale="1.0"
+ android:fromYScale="3.0" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_longAnimTime" />
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime" />
+</set>
diff --git a/core/res/res/anim/wallpaper_exit.xml b/core/res/res/anim/wallpaper_exit.xml
new file mode 100644
index 0000000..2306071
--- /dev/null
+++ b/core/res/res/anim/wallpaper_exit.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator">
+ <scale android:fromXScale="1.0" android:toXScale="3.0"
+ android:fromYScale="1.0" android:toYScale="3.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_longAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_longAnimTime"/>
+</set>
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_default.png b/core/res/res/drawable-hdpi/btn_code_lock_default.png
index 9f44d0f..df3137f 100644
--- a/core/res/res/drawable-hdpi/btn_code_lock_default.png
+++ b/core/res/res/drawable-hdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_touched.png b/core/res/res/drawable-hdpi/btn_code_lock_touched.png
index a4cc5bf..bf9e46a 100644
--- a/core/res/res/drawable-hdpi/btn_code_lock_touched.png
+++ b/core/res/res/drawable-hdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 86e6139..abb575c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -64,4 +64,21 @@
the slider is open. This can be set or unset depending how easily
the slider can be opened (for example, in a pocket or purse). -->
<bool name="config_bypass_keyguard_if_slider_open">true</bool>
+
+ <!-- Vibrator pattern for feedback about a long screen/key press -->
+ <integer-array name="config_longPressVibePattern">
+ <item>0</item>
+ <item>1</item>
+ <item>20</item>
+ <item>21</item>
+ </integer-array>
+
+ <!-- Vibrator pattern for feedback about touching a virtual key -->
+ <integer-array name="config_virtualKeyVibePattern">
+ <item>0</item>
+ <item>10</item>
+ <item>20</item>
+ <item>30</item>
+ </integer-array>
+
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 3950cb1..55f8167 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -160,6 +160,12 @@
<item name="windowExitAnimation">@anim/fade_out</item>
</style>
+ <!-- Standard animations for wallpapers. -->
+ <style name="Animation.Wallpaper">
+ <item name="windowEnterAnimation">@anim/wallpaper_enter</item>
+ <item name="windowExitAnimation">@anim/wallpaper_exit</item>
+ </style>
+
<!-- Status Bar Styles -->
<style name="TextAppearance.StatusBarTitle">
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 459ad37..ef1a1ea 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -399,6 +399,9 @@
<li><a href="<?cs var:toroot ?>guide/samples/NotePad/index.html">
<span class="en">Note Pad</span>
</a></li>
+ <li><a href="<?cs var:toroot ?>guide/samples/SearchableDictionary/index.html">
+ <span class="en">Searchable Dictionary</span>
+ </a></li>
<li><a href="<?cs var:toroot ?>guide/samples/Snake/index.html">
<span class="en">Snake</span>
</a></li>
diff --git a/docs/html/guide/samples/images/SearchableDictionary1.png b/docs/html/guide/samples/images/SearchableDictionary1.png
new file mode 100644
index 0000000..ebb4604
--- /dev/null
+++ b/docs/html/guide/samples/images/SearchableDictionary1.png
Binary files differ
diff --git a/docs/html/guide/samples/images/SearchableDictionary2.png b/docs/html/guide/samples/images/SearchableDictionary2.png
new file mode 100644
index 0000000..34746cd
--- /dev/null
+++ b/docs/html/guide/samples/images/SearchableDictionary2.png
Binary files differ
diff --git a/docs/html/guide/samples/index.jd b/docs/html/guide/samples/index.jd
index d8bbc41..6e79d50 100644
--- a/docs/html/guide/samples/index.jd
+++ b/docs/html/guide/samples/index.jd
@@ -33,6 +33,10 @@
<dd>An application for saving notes. Similar (but not identical) to the
<a href="{@docRoot}guide/tutorials/notepad/index.html">Notepad tutorial</a>.</dd>
+ <dt><a href="SearchableDictionary/index.html">Searchable Dictionary</a></dt>
+ <dd>A sample application that demonstrates Android's search framework,
+ including how to provide search suggestions for Quick Search Box.</dd>
+
<dt><a href="Snake/index.html">Snake</a></dt>
<dd>An implementation of the classic game "Snake."</dd>
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 77a126c..3a419b5 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -136,8 +136,17 @@
AudioFlinger::~AudioFlinger()
{
- mRecordThreads.clear();
- mPlaybackThreads.clear();
+ while (!mRecordThreads.isEmpty()) {
+ // closeInput() will remove first entry from mRecordThreads
+ closeInput(mRecordThreads.keyAt(0));
+ }
+ while (!mPlaybackThreads.isEmpty()) {
+ // closeOutput() will remove first entry from mPlaybackThreads
+ closeOutput(mPlaybackThreads.keyAt(0));
+ }
+ if (mAudioHardware) {
+ delete mAudioHardware;
+ }
}
diff --git a/media/tests/MediaFrameworkTest/res/layout/surface_view.xml b/media/tests/MediaFrameworkTest/res/layout/surface_view.xml
index c25e476..cbd1ff8 100644
--- a/media/tests/MediaFrameworkTest/res/layout/surface_view.xml
+++ b/media/tests/MediaFrameworkTest/res/layout/surface_view.xml
@@ -21,13 +21,12 @@
<FrameLayout
android:layout_width="fill_parent"
- android:layout_height="0px"
- android:layout_weight="1">
+ android:layout_height="fill_parent">
<SurfaceView
android:id="@+id/surface_view"
- android:layout_width="320dip"
- android:layout_height="240dip"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
android:layout_centerInParent="true"
/>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
index e65cf41..5e830a8 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
@@ -69,10 +69,6 @@
setContentView(R.layout.surface_view);
mSurfaceView = (SurfaceView)findViewById(R.id.surface_view);
ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
- lp.width = 320;
- lp.height = 240;
- mSurfaceView.setLayoutParams(lp);
- mSurfaceView.getHolder().setFixedSize(320, 240);
mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//Get the midi fd
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index ea42f53..30e2d6c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -435,9 +435,16 @@
@LargeTest
public void testLocalMp3PrepareAsyncCallback() throws Exception {
boolean onPrepareSuccess =
- CodecTest.prepareAsyncCallback(MediaNames.VIDEO_H263_AMR, false);
+ CodecTest.prepareAsyncCallback(MediaNames.MP3CBR, false);
assertTrue("LocalMp3prepareAsyncCallback", onPrepareSuccess);
}
+
+ @LargeTest
+ public void testLocalH263AMRPrepareAsyncCallback() throws Exception {
+ boolean onPrepareSuccess =
+ CodecTest.prepareAsyncCallback(MediaNames.VIDEO_H263_AMR, false);
+ assertTrue("testLocalH263AMRPrepareAsyncCallback", onPrepareSuccess);
+ }
@LargeTest
public void testStreamPrepareAsyncCallback() throws Exception {
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
index 3513215..ea14307 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
@@ -16,6 +16,7 @@
package com.android.providers.subscribedfeeds;
+import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -35,7 +36,10 @@
public void onReceive(Context context, Intent intent) {
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received intent " + intent);
- intent.setClass(context, SubscribedFeedsIntentService.class);
+ if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
+ setResultCode(Activity.RESULT_OK);
+ }
+ intent.setClass(context, SubscribedFeedsIntentService.class);
context.startService(intent);
}
}
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 2bd039f..7385359 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -36,17 +36,15 @@
private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
- private int mDockState;
- private boolean mPendingIntent;
+ private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ private boolean mSystemReady;
private final Context mContext;
public DockObserver(Context context) {
mContext = context;
-
- startObserving(DOCK_UEVENT_MATCH);
-
init(); // set initial status
+ startObserving(DOCK_UEVENT_MATCH);
}
@Override
@@ -55,55 +53,59 @@
Log.v(TAG, "Dock UEVENT: " + event.toString());
}
- try {
- update(Integer.parseInt(event.get("SWITCH_STATE")));
- } catch (NumberFormatException e) {
- Log.e(TAG, "Could not parse switch state from event " + event);
+ synchronized (this) {
+ try {
+ int newState = Integer.parseInt(event.get("SWITCH_STATE"));
+ if (newState != mDockState) {
+ mDockState = newState;
+ if (mSystemReady) {
+ update();
+ }
+ }
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Could not parse switch state from event " + event);
+ }
}
}
- private synchronized final void init() {
+ private final void init() {
char[] buffer = new char[1024];
- int newState = mDockState;
try {
FileReader file = new FileReader(DOCK_STATE_PATH);
int len = file.read(buffer, 0, 1024);
- newState = Integer.valueOf((new String(buffer, 0, len)).trim());
+ mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
} catch (FileNotFoundException e) {
Log.w(TAG, "This kernel does not have dock station support");
} catch (Exception e) {
Log.e(TAG, "" , e);
}
-
- update(newState);
}
- private synchronized final void update(int newState) {
- if (newState != mDockState) {
- mDockState = newState;
-
- mPendingIntent = true;
- mHandler.sendEmptyMessage(0);
+ void systemReady() {
+ synchronized (this) {
+ // don't bother broadcasting undocked here
+ if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ update();
+ }
+ mSystemReady = true;
}
}
- private synchronized final void sendIntent() {
- Log.d(TAG, "Broadcasting dock state " + mDockState);
-
- // Pack up the values and broadcast them to everyone
- Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
- intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
- mContext.sendStickyBroadcast(intent);
+ private final void update() {
+ mHandler.sendEmptyMessage(0);
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- if (mPendingIntent) {
- sendIntent();
- mPendingIntent = false;
+ synchronized (this) {
+ Log.d(TAG, "Broadcasting dock state " + mDockState);
+ // Pack up the values and broadcast them to everyone
+ Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
+ intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
+ mContext.sendStickyBroadcast(intent);
}
}
};
diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java
index ceef39f..4dfeb9d 100644
--- a/services/java/com/android/server/SensorService.java
+++ b/services/java/com/android/server/SensorService.java
@@ -84,12 +84,16 @@
if (hasSensor(sensor)) {
removeSensor(sensor);
try {
- deactivateIfUnused(sensor);
+ deactivateIfUnusedLocked(sensor);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException in binderDied");
}
}
}
+ if (mListeners.size() == 0) {
+ _sensors_control_wake();
+ _sensors_control_close();
+ }
mListeners.notify();
}
}
@@ -102,9 +106,12 @@
}
public Bundle getDataChannel() throws RemoteException {
- return _sensors_control_open();
+ // synchronize so we do not require sensor HAL to be thread-safe.
+ synchronized(mListeners) {
+ return _sensors_control_open();
+ }
}
-
+
public boolean enableSensor(IBinder binder, String name, int sensor, int enable)
throws RemoteException {
if (localLOGV) Log.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable);
@@ -163,7 +170,7 @@
l.addSensor(sensor, enable);
} else {
l.removeSensor(sensor);
- deactivateIfUnused(sensor);
+ deactivateIfUnusedLocked(sensor);
if (l.mSensors == 0) {
mListeners.remove(l);
binder.unlinkToDeath(l, 0);
@@ -173,12 +180,13 @@
if (mListeners.size() == 0) {
_sensors_control_wake();
+ _sensors_control_close();
}
}
return true;
}
- void deactivateIfUnused(int sensor) throws RemoteException {
+ private void deactivateIfUnusedLocked(int sensor) throws RemoteException {
int size = mListeners.size();
for (int i=0 ; i<size ; i++) {
if (mListeners.get(i).hasSensor(sensor))
@@ -187,10 +195,11 @@
_sensors_control_activate(sensor, false);
}
- ArrayList<Listener> mListeners = new ArrayList<Listener>();
+ private ArrayList<Listener> mListeners = new ArrayList<Listener>();
private static native int _sensors_control_init();
private static native Bundle _sensors_control_open();
+ private static native int _sensors_control_close();
private static native boolean _sensors_control_activate(int sensor, boolean activate);
private static native int _sensors_control_set_delay(int ms);
private static native int _sensors_control_wake();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 95edbeb..df01c61 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -392,6 +392,7 @@
if (wallpaper != null) wallpaper.systemReady();
if (battery != null) battery.systemReady();
if (connectivity != null) connectivity.systemReady();
+ if (dock != null) dock.systemReady();
Watchdog.getInstance().start();
Looper.loop();
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 3c62aa0..c101463 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -32,6 +32,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.FileObserver;
@@ -232,6 +233,16 @@
mWidth = width;
mHeight = height;
saveSettingsLocked();
+ if (mWallpaperConnection != null) {
+ if (mWallpaperConnection.mEngine != null) {
+ try {
+ mWallpaperConnection.mEngine.setDesiredSize(
+ width, height);
+ } catch (RemoteException e) {
+ }
+ notifyCallbacksLocked();
+ }
+ }
}
}
}
@@ -248,9 +259,14 @@
}
}
- public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb) {
+ public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
+ Bundle outParams) {
synchronized (mLock) {
try {
+ if (outParams != null) {
+ outParams.putInt("width", mWidth);
+ outParams.putInt("height", mHeight);
+ }
mCallbacks.register(cb);
File f = WALLPAPER_FILE;
if (!f.exists()) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 4321b0d..81e0136 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -412,6 +412,8 @@
// to another, and this is the higher one in Z-order.
WindowState mUpperWallpaperTarget = null;
int mWallpaperAnimLayerAdjustment;
+ float mLastWallpaperX;
+ float mLastWallpaperY;
AppWindowToken mFocusedApp = null;
@@ -1371,6 +1373,11 @@
// what is below it for later.
foundW = foundI > 0 ? (WindowState)localmWindows.get(foundI-1) : null;
+ if (visible) {
+ mLastWallpaperX = mWallpaperTarget.mWallpaperX;
+ mLastWallpaperY = mWallpaperTarget.mWallpaperY;
+ }
+
// Start stepping backwards from here, ensuring that our wallpaper windows
// are correctly placed.
int curTokenIndex = mWallpaperTokens.size();
@@ -1383,8 +1390,7 @@
WindowState wallpaper = token.windows.get(curWallpaperIndex);
if (visible) {
- updateWallpaperOffsetLocked(mWallpaperTarget,
- wallpaper, dw, dh);
+ updateWallpaperOffsetLocked(wallpaper, dw, dh);
}
// First, make sure the client has the current visibility
@@ -1455,36 +1461,35 @@
}
}
- boolean updateWallpaperOffsetLocked(WindowState target,
- WindowState wallpaperWin, int dw, int dh) {
+ boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh) {
boolean changed = false;
boolean rawChanged = false;
- if (target.mWallpaperX >= 0) {
+ if (mLastWallpaperX >= 0) {
int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
- int offset = availw > 0 ? -(int)(availw*target.mWallpaperX+.5f) : 0;
+ int offset = availw > 0 ? -(int)(availw*mLastWallpaperX+.5f) : 0;
changed = wallpaperWin.mXOffset != offset;
if (changed) {
if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
+ wallpaperWin + " x: " + offset);
wallpaperWin.mXOffset = offset;
}
- if (wallpaperWin.mWallpaperX != target.mWallpaperX) {
- wallpaperWin.mWallpaperX = target.mWallpaperX;
+ if (wallpaperWin.mWallpaperX != mLastWallpaperX) {
+ wallpaperWin.mWallpaperX = mLastWallpaperX;
rawChanged = true;
}
}
- if (target.mWallpaperY >= 0) {
+ if (mLastWallpaperY >= 0) {
int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh;
- int offset = availh > 0 ? -(int)(availh*target.mWallpaperY+.5f) : 0;
+ int offset = availh > 0 ? -(int)(availh*mLastWallpaperY+.5f) : 0;
if (wallpaperWin.mYOffset != offset) {
if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
+ wallpaperWin + " y: " + offset);
changed = true;
wallpaperWin.mYOffset = offset;
}
- if (wallpaperWin.mWallpaperY != target.mWallpaperY) {
- wallpaperWin.mWallpaperY = target.mWallpaperY;
+ if (wallpaperWin.mWallpaperY != mLastWallpaperY) {
+ wallpaperWin.mWallpaperY = mLastWallpaperY;
rawChanged = true;
}
}
@@ -1511,6 +1516,8 @@
WindowState target = mWallpaperTarget;
if (target != null) {
+ mLastWallpaperX = target.mWallpaperX;
+ mLastWallpaperY = target.mWallpaperY;
int curTokenIndex = mWallpaperTokens.size();
while (curTokenIndex > 0) {
curTokenIndex--;
@@ -1519,7 +1526,7 @@
while (curWallpaperIndex > 0) {
curWallpaperIndex--;
WindowState wallpaper = token.windows.get(curWallpaperIndex);
- if (updateWallpaperOffsetLocked(target, wallpaper, dw, dh)) {
+ if (updateWallpaperOffsetLocked(wallpaper, dw, dh)) {
wallpaper.computeShownFrameLocked();
changed = true;
}
@@ -1545,8 +1552,7 @@
curWallpaperIndex--;
WindowState wallpaper = token.windows.get(curWallpaperIndex);
if (visible) {
- updateWallpaperOffsetLocked(mWallpaperTarget,
- wallpaper, dw, dh);
+ updateWallpaperOffsetLocked(wallpaper, dw, dh);
}
if (wallpaper.mWallpaperVisible != visible) {
@@ -2188,6 +2194,10 @@
}
newConfig = updateOrientationFromAppTokensLocked(null, null);
performLayoutAndPlaceSurfacesLocked();
+ if (displayed && win.mIsWallpaper) {
+ updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
+ mDisplay.getHeight());
+ }
if (win.mAppToken != null) {
win.mAppToken.updateReportedVisibilityLocked();
}
@@ -3010,6 +3020,23 @@
return;
}
+ // If this is a translucent or wallpaper window, then don't
+ // show a starting window -- the current effect (a full-screen
+ // opaque starting window that fades away to the real contents
+ // when it is ready) does not work for this.
+ if (theme != 0) {
+ AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
+ com.android.internal.R.styleable.Window);
+ if (ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
+ return;
+ }
+ if (ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
+ return;
+ }
+ }
+
mStartingIconInTransition = true;
wtoken.startingData = new StartingData(
pkg, theme, nonLocalizedLabel,
@@ -6544,10 +6571,9 @@
visibleInsets.right = frame.right-visible.right;
visibleInsets.bottom = frame.bottom-visible.bottom;
- if (mIsWallpaper && (fw != frame.width() || fh != frame.height())
- && mWallpaperTarget != null) {
- updateWallpaperOffsetLocked(mWallpaperTarget, this,
- mDisplay.getWidth(), mDisplay.getHeight());
+ if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
+ updateWallpaperOffsetLocked(this, mDisplay.getWidth(),
+ mDisplay.getHeight());
}
if (localLOGV) {
@@ -9851,6 +9877,10 @@
pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget);
pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
pw.print(" mWallpaperTarget="); pw.println(mWallpaperTarget);
+ if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
+ pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
+ pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
+ }
pw.print(" mInTouchMode="); pw.println(mInTouchMode);
pw.print(" mSystemBooted="); pw.print(mSystemBooted);
pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
@@ -9865,6 +9895,8 @@
pw.print(mInputMethodAnimLayerAdjustment);
pw.print(" mWallpaperAnimLayerAdjustment=");
pw.println(mWallpaperAnimLayerAdjustment);
+ pw.print(" mLastWallpaperX="); pw.print(mLastWallpaperX);
+ pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
diff --git a/services/jni/com_android_server_SensorService.cpp b/services/jni/com_android_server_SensorService.cpp
index 7390786..3911d1f 100644
--- a/services/jni/com_android_server_SensorService.cpp
+++ b/services/jni/com_android_server_SensorService.cpp
@@ -111,6 +111,15 @@
return bundle;
}
+static jint
+android_close(JNIEnv *env, jclass clazz)
+{
+ if (sSensorDevice->close_data_source)
+ return sSensorDevice->close_data_source(sSensorDevice);
+ else
+ return 0;
+}
+
static jboolean
android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate)
{
@@ -135,6 +144,7 @@
static JNINativeMethod gMethods[] = {
{"_sensors_control_init", "()I", (void*) android_init },
{"_sensors_control_open", "()Landroid/os/Bundle;", (void*) android_open },
+ {"_sensors_control_close", "()I", (void*) android_close },
{"_sensors_control_activate", "(IZ)Z", (void*) android_activate },
{"_sensors_control_wake", "()I", (void*) android_data_wake },
{"_sensors_control_set_delay","(I)I", (void*) android_set_delay },
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 598f945..14b1563d 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -421,4 +421,6 @@
static public final int RESULT_ERROR_NULL_PDU = 3;
/** Failed because service is currently unavailable */
static public final int RESULT_ERROR_NO_SERVICE = 4;
+ /** Failed because we reached the sending queue limit. {@hide} */
+ static public final int RESULT_ERROR_LIMIT_EXCEEDED = 5;
}
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 79c4b41..ece708a 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -280,16 +280,8 @@
if (!dataEnabled[apnId]) {
dataEnabled[apnId] = true;
enabledCount++;
- if (enabledCount == 1) {
- if (onTrySetupData(null) == false) {
- // failed to setup data - note we can't optimize by only adj
- // these after a successfull call. dataEnabled must be set
- // prior or we think data is not available.
- dataEnabled[apnId] = false;
- enabledCount--;
- }
- }
}
+ onTrySetupData(null);
} else {
// disable
if (dataEnabled[apnId]) {
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index d66c20b..bbfc6c9 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -61,6 +61,7 @@
import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
+import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
public abstract class SMSDispatcher extends Handler {
@@ -105,6 +106,9 @@
/** Alert is timeout */
static final protected int EVENT_ALERT_TIMEOUT = 9;
+ /** Stop the sending */
+ static final protected int EVENT_STOP_SENDING = 10;
+
protected Phone mPhone;
protected Context mContext;
protected ContentResolver mResolver;
@@ -120,6 +124,8 @@
private static final int SEND_RETRY_DELAY = 2000;
/** single part SMS */
private static final int SINGLE_PART_SMS = 1;
+ /** Message sending queue limit */
+ private static final int MO_MSG_QUEUE_LIMIT = 5;
/**
* Message reference for a CONCATENATED_8_BIT_REFERENCE or
@@ -130,7 +136,7 @@
private SmsCounter mCounter;
- private SmsTracker mSTracker;
+ private ArrayList mSTrackers = new ArrayList(MO_MSG_QUEUE_LIMIT);
/** Wake lock to ensure device stays awake while dispatching the SMS intent. */
private PowerManager.WakeLock mWakeLock;
@@ -214,7 +220,6 @@
mContext = phone.getContext();
mResolver = mContext.getContentResolver();
mCm = phone.mCM;
- mSTracker = null;
createWakelock();
@@ -330,17 +335,41 @@
case EVENT_ALERT_TIMEOUT:
((AlertDialog)(msg.obj)).dismiss();
msg.obj = null;
- mSTracker = null;
+ if (mSTrackers.isEmpty() == false) {
+ try {
+ SmsTracker sTracker = (SmsTracker)mSTrackers.remove(0);
+ sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
+ } catch (CanceledException ex) {
+ Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
+ }
+ }
+ if (Config.LOGD) {
+ Log.d(TAG, "EVENT_ALERT_TIMEOUT, message stop sending");
+ }
break;
case EVENT_SEND_CONFIRMED_SMS:
- if (mSTracker!=null) {
- if (isMultipartTracker(mSTracker)) {
- sendMultipartSms(mSTracker);
+ if (mSTrackers.isEmpty() == false) {
+ SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1);
+ if (isMultipartTracker(sTracker)) {
+ sendMultipartSms(sTracker);
} else {
- sendSms(mSTracker);
+ sendSms(sTracker);
}
- mSTracker = null;
+ removeMessages(EVENT_ALERT_TIMEOUT, msg.obj);
+ }
+ break;
+
+ case EVENT_STOP_SENDING:
+ if (mSTrackers.isEmpty() == false) {
+ // Remove the latest one.
+ try {
+ SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1);
+ sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
+ } catch (CanceledException ex) {
+ Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
+ }
+ removeMessages(EVENT_ALERT_TIMEOUT, msg.obj);
}
break;
}
@@ -693,6 +722,15 @@
* An SmsTracker for the current message.
*/
protected void handleReachSentLimit(SmsTracker tracker) {
+ if (mSTrackers.size() >= MO_MSG_QUEUE_LIMIT) {
+ // Deny the sending when the queue limit is reached.
+ try {
+ tracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
+ } catch (CanceledException ex) {
+ Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
+ }
+ return;
+ }
Resources r = Resources.getSystem();
@@ -702,13 +740,13 @@
.setTitle(r.getString(R.string.sms_control_title))
.setMessage(appName + " " + r.getString(R.string.sms_control_message))
.setPositiveButton(r.getString(R.string.sms_control_yes), mListener)
- .setNegativeButton(r.getString(R.string.sms_control_no), null)
+ .setNegativeButton(r.getString(R.string.sms_control_no), mListener)
.create();
d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
d.show();
- mSTracker = tracker;
+ mSTrackers.add(tracker);
sendMessageDelayed ( obtainMessage(EVENT_ALERT_TIMEOUT, d),
DEFAULT_SMS_TIMOUEOUT);
}
@@ -819,6 +857,9 @@
if (which == DialogInterface.BUTTON_POSITIVE) {
Log.d(TAG, "click YES to send out sms");
sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS));
+ } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+ Log.d(TAG, "click NO to stop sending");
+ sendMessage(obtainMessage(EVENT_STOP_SENDING));
}
}
};
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 3cabd2d..ffaa1cd 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -568,8 +568,7 @@
private boolean retryAfterDisconnected(String reason) {
boolean retry = true;
- if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
- Phone.REASON_DATA_DISABLED.equals(reason) ) {
+ if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) {
retry = false;
}
return retry;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index d057dfe..0215ab2 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -1010,8 +1010,7 @@
private boolean retryAfterDisconnected(String reason) {
boolean retry = true;
- if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
- Phone.REASON_DATA_DISABLED.equals(reason) ) {
+ if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) {
retry = false;
}
return retry;
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index dbcef6d..b00d8b0 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1819,6 +1819,19 @@
AaptDir::print();
}
+sp<AaptDir> AaptAssets::resDir(const String8& name)
+{
+ const Vector<sp<AaptDir> >& dirs = mDirs;
+ const size_t N = dirs.size();
+ for (size_t i=0; i<N; i++) {
+ const sp<AaptDir>& d = dirs.itemAt(i);
+ if (d->getLeaf() == name) {
+ return d;
+ }
+ }
+ return NULL;
+}
+
bool
valid_symbol_name(const String8& symbol)
{
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 32efa4e..865efd1 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -508,6 +508,7 @@
void print() const;
inline const Vector<sp<AaptDir> >& resDirs() { return mDirs; }
+ sp<AaptDir> resDir(const String8& name);
inline sp<AaptAssets> getOverlay() { return mOverlay; }
inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; }
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index a671bd7..234e5b2 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -39,7 +39,7 @@
mRequireLocalization(false), mPseudolocalize(false),
mValues(false),
mCompressionMethod(0), mOutputAPKFile(NULL),
- mAssetSourceDir(NULL),
+ mAssetSourceDir(NULL), mProguardFile(NULL),
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
mRClassDir(NULL), mResourceIntermediatesDir(NULL),
mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
@@ -88,6 +88,8 @@
*/
const char* getAssetSourceDir() const { return mAssetSourceDir; }
void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; }
+ const char* getProguardFile() const { return mProguardFile; }
+ void setProguardFile(const char* file) { mProguardFile = file; }
const android::Vector<const char*>& getResourceSourceDirs() const { return mResourceSourceDirs; }
void addResourceSourceDir(const char* dir) { mResourceSourceDirs.insertAt(dir,0); }
const char* getAndroidManifestFile() const { return mAndroidManifestFile; }
@@ -161,6 +163,7 @@
int mCompressionMethod;
const char* mOutputAPKFile;
const char* mAssetSourceDir;
+ const char* mProguardFile;
const char* mAndroidManifestFile;
const char* mPublicOutputFile;
const char* mRClassDir;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 790b474..f2cdf75 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -233,7 +233,7 @@
return -1;
}
-static String8 getAttribute(const ResXMLTree& tree, const char* ns,
+String8 getAttribute(const ResXMLTree& tree, const char* ns,
const char* attr, String8* outError)
{
ssize_t idx = tree.indexOfAttribute(ns, attr);
@@ -1158,6 +1158,12 @@
}
}
+ // Write out the ProGuard file
+ err = writeProguardFile(bundle, assets);
+ if (err < 0) {
+ goto bail;
+ }
+
// Write the apk
if (outputAPKFile) {
err = writeAPK(bundle, assets, String8(outputAPKFile));
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 882714c..e61010c 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -59,9 +59,9 @@
" [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
" [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
" [--max-sdk-version VAL] [--app-version VAL] \\\n"
- " [--app-version-name TEXT] \\\n"
+ " [--app-version-name TEXT]\\\n"
" [-I base-package [-I base-package ...]] \\\n"
- " [-A asset-source-dir] [-P public-definitions-file] \\\n"
+ " [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \\\n"
" [-S resource-sources [-S resource-sources ...]] "
" [-F apk-file] [-J R-file-dir] \\\n"
" [raw-files-dir [raw-files-dir] ...]\n"
@@ -109,6 +109,7 @@
" -z require localization of resource attributes marked with\n"
" localization=\"suggested\"\n"
" -A additional directory in which to find raw asset files\n"
+ " -G A file to output proguard options into.\n"
" -F specify the apk file to output\n"
" -I add an existing package to base include set\n"
" -J specify where to output R.java resource constant definitions\n"
@@ -274,6 +275,17 @@
convertPath(argv[0]);
bundle.setAssetSourceDir(argv[0]);
break;
+ case 'G':
+ argc--;
+ argv++;
+ if (!argc) {
+ fprintf(stderr, "ERROR: No argument supplied for '-G' option\n");
+ wantUsage = true;
+ goto bail;
+ }
+ convertPath(argv[0]);
+ bundle.setProguardFile(argv[0]);
+ break;
case 'I':
argc--;
argv++;
diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h
index 34ca5e5..3ba4f39 100644
--- a/tools/aapt/Main.h
+++ b/tools/aapt/Main.h
@@ -33,6 +33,8 @@
extern android::status_t writeResourceSymbols(Bundle* bundle,
const sp<AaptAssets>& assets, const String8& pkgName, bool includePrivate);
+extern android::status_t writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets);
+
extern bool isValidResourceType(const String8& type);
ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
@@ -41,4 +43,7 @@
int dumpResources(Bundle* bundle);
+String8 getAttribute(const ResXMLTree& tree, const char* ns,
+ const char* attr, String8* outError);
+
#endif // __MAIN_H
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index e8410cd..4c9853d 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1630,3 +1630,230 @@
return NO_ERROR;
}
+
+
+
+class ProguardKeepSet
+{
+public:
+ // { rule --> { file locations } }
+ KeyedVector<String8, SortedVector<String8> > rules;
+
+ void add(const String8& rule, const String8& where);
+};
+
+void ProguardKeepSet::add(const String8& rule, const String8& where)
+{
+ ssize_t index = rules.indexOfKey(rule);
+ if (index < 0) {
+ index = rules.add(rule, SortedVector<String8>());
+ }
+ rules.editValueAt(index).add(where);
+}
+
+status_t
+writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
+{
+ status_t err;
+ ResXMLTree tree;
+ size_t len;
+ ResXMLTree::event_code_t code;
+ int depth = 0;
+ bool inApplication = false;
+ String8 error;
+ sp<AaptGroup> assGroup;
+ sp<AaptFile> assFile;
+ String8 pkg;
+
+ // First, look for a package file to parse. This is required to
+ // be able to generate the resource information.
+ assGroup = assets->getFiles().valueFor(String8("AndroidManifest.xml"));
+ if (assGroup == NULL) {
+ fprintf(stderr, "ERROR: No AndroidManifest.xml file found.\n");
+ return -1;
+ }
+
+ if (assGroup->getFiles().size() != 1) {
+ fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
+ assGroup->getFiles().valueAt(0)->getPrintableSource().string());
+ }
+
+ assFile = assGroup->getFiles().valueAt(0);
+
+ err = parseXMLResource(assFile, &tree);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ tree.restart();
+
+ while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ if (code == ResXMLTree::END_TAG) {
+ if (/* name == "Application" && */ depth == 2) {
+ inApplication = false;
+ }
+ depth--;
+ continue;
+ }
+ if (code != ResXMLTree::START_TAG) {
+ continue;
+ }
+ depth++;
+ String8 tag(tree.getElementName(&len));
+ // printf("Depth %d tag %s\n", depth, tag.string());
+ if (depth == 1) {
+ if (tag != "manifest") {
+ fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
+ return -1;
+ }
+ pkg = getAttribute(tree, NULL, "package", NULL);
+ } else if (depth == 2 && tag == "application") {
+ inApplication = true;
+ }
+ if (inApplication) {
+ if (tag == "application" || tag == "activity" || tag == "service" || tag == "receiver"
+ || tag == "provider") {
+ String8 name = getAttribute(tree, "http://schemas.android.com/apk/res/android",
+ "name", &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR: %s\n", error.string());
+ return -1;
+ }
+ // asdf --> package.asdf
+ // .asdf .a.b --> package.asdf package.a.b
+ // asdf.adsf --> asdf.asdf
+ String8 rule("-keep class ");
+ const char* p = name.string();
+ const char* q = strchr(p, '.');
+ if (p == q) {
+ rule += pkg;
+ rule += name;
+ } else if (q == NULL) {
+ rule += pkg;
+ rule += ".";
+ rule += name;
+ } else {
+ rule += name;
+ }
+
+ String8 location = tag;
+ location += " ";
+ location += assFile->getSourceFile();
+ char lineno[20];
+ sprintf(lineno, ":%d", tree.getLineNumber());
+ location += lineno;
+
+ keep->add(rule, location);
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t
+writeProguardForLayout(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile)
+{
+ status_t err;
+ ResXMLTree tree;
+ size_t len;
+ ResXMLTree::event_code_t code;
+
+ err = parseXMLResource(layoutFile, &tree);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ tree.restart();
+
+ while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ if (code != ResXMLTree::START_TAG) {
+ continue;
+ }
+ String8 tag(tree.getElementName(&len));
+
+ // If there is no '.', we'll assume that it's one of the built in names.
+ if (strchr(tag.string(), '.')) {
+ String8 rule("-keep class ");
+ rule += tag;
+ rule += " { <init>(...); }";
+
+ String8 location("view ");
+ location += layoutFile->getSourceFile();
+ char lineno[20];
+ sprintf(lineno, ":%d", tree.getLineNumber());
+ location += lineno;
+
+ keep->add(rule, location);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t
+writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
+{
+ status_t err;
+ sp<AaptDir> layout = assets->resDir(String8("layout"));
+
+ if (layout != NULL) {
+ const KeyedVector<String8,sp<AaptGroup> > groups = layout->getFiles();
+ const size_t N = groups.size();
+ for (size_t i=0; i<N; i++) {
+ const sp<AaptGroup>& group = groups.valueAt(i);
+ const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles();
+ const size_t M = files.size();
+ for (size_t j=0; j<M; j++) {
+ err = writeProguardForLayout(keep, files.valueAt(j));
+ if (err < 0) {
+ return err;
+ }
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t
+writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets)
+{
+ status_t err = -1;
+
+ if (!bundle->getProguardFile()) {
+ return NO_ERROR;
+ }
+
+ ProguardKeepSet keep;
+
+ err = writeProguardForAndroidManifest(&keep, assets);
+ if (err < 0) {
+ return err;
+ }
+
+ err = writeProguardForLayouts(&keep, assets);
+ if (err < 0) {
+ return err;
+ }
+
+ FILE* fp = fopen(bundle->getProguardFile(), "w+");
+ if (fp == NULL) {
+ fprintf(stderr, "ERROR: Unable to open class file %s: %s\n",
+ bundle->getProguardFile(), strerror(errno));
+ return UNKNOWN_ERROR;
+ }
+
+ const KeyedVector<String8, SortedVector<String8> >& rules = keep.rules;
+ const size_t N = rules.size();
+ for (size_t i=0; i<N; i++) {
+ const SortedVector<String8>& locations = rules.valueAt(i);
+ const size_t M = locations.size();
+ for (size_t j=0; j<M; j++) {
+ fprintf(fp, "# %s\n", locations.itemAt(j).string());
+ }
+ fprintf(fp, "%s\n\n", rules.keyAt(i).string());
+ }
+ fclose(fp);
+
+ return err;
+}