diff options
79 files changed, 1248 insertions, 857 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index 9381437f5dd0..fb334fce090e 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -116,6 +116,7 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/fonts/DroidSans*) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/fonts/DroidSans*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d2facdcc172c..8afe9bf0468e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -490,6 +490,15 @@ public final class ActivityThread { // Formatting for checkin service - update version if row format changes private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1; + private void updatePendingConfiguration(Configuration config) { + synchronized (mPackages) { + if (mPendingConfiguration == null || + mPendingConfiguration.isOtherSeqNewer(config)) { + mPendingConfiguration = config; + } + } + } + public final void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges) { queueOrSendMessage( @@ -530,8 +539,8 @@ public final class ActivityThread { // we use token to identify this activity without having to send the // activity itself back to the activity manager. (matters more with ipc) public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, - ActivityInfo info, CompatibilityInfo compatInfo, Bundle state, - List<ResultInfo> pendingResults, + ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, + Bundle state, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { ActivityClientRecord r = new ActivityClientRecord(); @@ -553,6 +562,8 @@ public final class ActivityThread { r.profileFd = profileFd; r.autoStopProfiler = autoStopProfiler; + updatePendingConfiguration(curConfig); + queueOrSendMessage(H.LAUNCH_ACTIVITY, r); } @@ -697,12 +708,7 @@ public final class ActivityThread { } public void scheduleConfigurationChanged(Configuration config) { - synchronized (mPackages) { - if (mPendingConfiguration == null || - mPendingConfiguration.isOtherSeqNewer(config)) { - mPendingConfiguration = config; - } - } + updatePendingConfiguration(config); queueOrSendMessage(H.CONFIGURATION_CHANGED, config); } @@ -1966,6 +1972,9 @@ public final class ActivityThread { mProfiler.autoStopProfiler = r.autoStopProfiler; } + // Make sure we are running with the most recent config. + handleConfigurationChanged(null, null); + if (localLOGV) Slog.v( TAG, "Handling launch of " + r); Activity a = performLaunchActivity(r, customIntent); diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index cde06cd891de..c4a4feaff611 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -132,6 +132,7 @@ public abstract class ApplicationThreadNative extends Binder IBinder b = data.readStrongBinder(); int ident = data.readInt(); ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data); + Configuration curConfig = Configuration.CREATOR.createFromParcel(data); CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data); Bundle state = data.readBundle(); List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR); @@ -142,7 +143,7 @@ public abstract class ApplicationThreadNative extends Binder ParcelFileDescriptor profileFd = data.readInt() != 0 ? data.readFileDescriptor() : null; boolean autoStopProfiler = data.readInt() != 0; - scheduleLaunchActivity(intent, b, ident, info, compatInfo, state, ri, pi, + scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, state, ri, pi, notResumed, isForward, profileName, profileFd, autoStopProfiler); return true; } @@ -630,10 +631,10 @@ class ApplicationThreadProxy implements IApplicationThread { } public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, - ActivityInfo info, CompatibilityInfo compatInfo, Bundle state, - List<ResultInfo> pendingResults, - List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, - String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) + ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, + Bundle state, List<ResultInfo> pendingResults, + List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, + String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); @@ -641,6 +642,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeStrongBinder(token); data.writeInt(ident); info.writeToParcel(data, 0); + curConfig.writeToParcel(data, 0); compatInfo.writeToParcel(data, 0); data.writeBundle(state); data.writeTypedList(pendingResults); diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 5d200b46a4e0..1253fe7896c4 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -53,10 +53,10 @@ public interface IApplicationThread extends IInterface { void scheduleResumeActivity(IBinder token, boolean isForward) throws RemoteException; void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException; void scheduleLaunchActivity(Intent intent, IBinder token, int ident, - ActivityInfo info, CompatibilityInfo compatInfo, Bundle state, - List<ResultInfo> pendingResults, - List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, - String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) + ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, + Bundle state, List<ResultInfo> pendingResults, + List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, + String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException; void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, int configChanges, diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java index 8aee65c5fc1b..615e8cea64c4 100644 --- a/core/java/android/app/SharedPreferencesImpl.java +++ b/core/java/android/app/SharedPreferencesImpl.java @@ -29,6 +29,7 @@ import dalvik.system.BlockGuard; import org.xmlpull.v1.XmlPullParserException; +import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -107,7 +108,8 @@ final class SharedPreferencesImpl implements SharedPreferences { FileStatus stat = new FileStatus(); if (FileUtils.getFileStatus(mFile.getPath(), stat) && mFile.canRead()) { try { - FileInputStream str = new FileInputStream(mFile); + BufferedInputStream str = new BufferedInputStream( + new FileInputStream(mFile), 16*1024); map = XmlUtils.readMapXml(str); str.close(); } catch (XmlPullParserException e) { diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 8057d4bd260f..e452f1fa3162 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -22,10 +22,6 @@ import android.content.pm.ProviderInfo; import android.content.res.AssetFileDescriptor; import android.content.res.Configuration; import android.database.Cursor; -import android.database.CursorToBulkCursorAdaptor; -import android.database.CursorWindow; -import android.database.IBulkCursor; -import android.database.IContentObserver; import android.database.SQLException; import android.net.Uri; import android.os.AsyncTask; @@ -168,22 +164,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 { return ContentProvider.this; } - /** - * Remote version of a query, which returns an IBulkCursor. The bulk - * cursor should be wrapped with BulkCursorToCursorAdaptor before use. - */ - public IBulkCursor bulkQuery(Uri uri, String[] projection, - String selection, String[] selectionArgs, String sortOrder, - IContentObserver observer, CursorWindow window) { - enforceReadPermission(uri); - Cursor cursor = ContentProvider.this.query(uri, projection, - selection, selectionArgs, sortOrder); - if (cursor == null) { - return null; - } - return new CursorToBulkCursorAdaptor(cursor, observer, - ContentProvider.this.getClass().getName(), - hasWritePermission(uri), window); + @Override + public String getProviderName() { + return getContentProvider().getClass().getName(); } public Cursor query(Uri uri, String[] projection, diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index abeeb7406957..064755e95fbd 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -20,6 +20,7 @@ import android.content.res.AssetFileDescriptor; import android.database.BulkCursorNative; import android.database.BulkCursorToCursorAdaptor; import android.database.Cursor; +import android.database.CursorToBulkCursorAdaptor; import android.database.CursorWindow; import android.database.DatabaseUtils; import android.database.IBulkCursor; @@ -65,6 +66,13 @@ abstract public class ContentProviderNative extends Binder implements IContentPr return new ContentProviderProxy(obj); } + /** + * Gets the name of the content provider. + * Should probably be part of the {@link IContentProvider} interface. + * @return The content provider name. + */ + public abstract String getProviderName(); + @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { @@ -98,33 +106,23 @@ abstract public class ContentProviderNative extends Binder implements IContentPr } String sortOrder = data.readString(); - IContentObserver observer = IContentObserver.Stub. - asInterface(data.readStrongBinder()); + IContentObserver observer = IContentObserver.Stub.asInterface( + data.readStrongBinder()); CursorWindow window = CursorWindow.CREATOR.createFromParcel(data); - // Flag for whether caller wants the number of - // rows in the cursor and the position of the - // "_id" column index (or -1 if non-existent) - // Only to be returned if binder != null. - boolean wantsCursorMetadata = data.readInt() != 0; - - IBulkCursor bulkCursor = bulkQuery(url, projection, selection, - selectionArgs, sortOrder, observer, window); - if (bulkCursor != null) { - final IBinder binder = bulkCursor.asBinder(); - if (wantsCursorMetadata) { - final int count = bulkCursor.count(); - final int index = BulkCursorToCursorAdaptor.findRowIdColumnIndex( - bulkCursor.getColumnNames()); - - reply.writeNoException(); - reply.writeStrongBinder(binder); - reply.writeInt(count); - reply.writeInt(index); - } else { - reply.writeNoException(); - reply.writeStrongBinder(binder); - } + Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder); + if (cursor != null) { + CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor( + cursor, observer, getProviderName(), window); + final IBinder binder = adaptor.asBinder(); + final int count = adaptor.count(); + final int index = BulkCursorToCursorAdaptor.findRowIdColumnIndex( + adaptor.getColumnNames()); + + reply.writeNoException(); + reply.writeStrongBinder(binder); + reply.writeInt(count); + reply.writeInt(index); } else { reply.writeNoException(); reply.writeStrongBinder(null); @@ -324,332 +322,310 @@ final class ContentProviderProxy implements IContentProvider return mRemote; } - // Like bulkQuery() but sets up provided 'adaptor' if not null. - private IBulkCursor bulkQueryInternal( - Uri url, String[] projection, - String selection, String[] selectionArgs, String sortOrder, - IContentObserver observer, CursorWindow window, - BulkCursorToCursorAdaptor adaptor) throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - int length = 0; - if (projection != null) { - length = projection.length; - } - data.writeInt(length); - for (int i = 0; i < length; i++) { - data.writeString(projection[i]); - } - data.writeString(selection); - if (selectionArgs != null) { - length = selectionArgs.length; - } else { - length = 0; - } - data.writeInt(length); - for (int i = 0; i < length; i++) { - data.writeString(selectionArgs[i]); - } - data.writeString(sortOrder); - data.writeStrongBinder(observer.asBinder()); - window.writeToParcel(data, 0); - - // Flag for whether or not we want the number of rows in the - // cursor and the position of the "_id" column index (or -1 if - // non-existent). Only to be returned if binder != null. - final boolean wantsCursorMetadata = (adaptor != null); - data.writeInt(wantsCursorMetadata ? 1 : 0); - - mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); + public Cursor query(Uri url, String[] projection, String selection, + String[] selectionArgs, String sortOrder) throws RemoteException { + CursorWindow window = new CursorWindow(false /* window will be used remotely */); + try { + BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); + + url.writeToParcel(data, 0); + int length = 0; + if (projection != null) { + length = projection.length; + } + data.writeInt(length); + for (int i = 0; i < length; i++) { + data.writeString(projection[i]); + } + data.writeString(selection); + if (selectionArgs != null) { + length = selectionArgs.length; + } else { + length = 0; + } + data.writeInt(length); + for (int i = 0; i < length; i++) { + data.writeString(selectionArgs[i]); + } + data.writeString(sortOrder); + data.writeStrongBinder(adaptor.getObserver().asBinder()); + window.writeToParcel(data, 0); - DatabaseUtils.readExceptionFromParcel(reply); + mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); - IBulkCursor bulkCursor = null; - IBinder bulkCursorBinder = reply.readStrongBinder(); - if (bulkCursorBinder != null) { - bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder); + DatabaseUtils.readExceptionFromParcel(reply); - if (wantsCursorMetadata) { - int rowCount = reply.readInt(); - int idColumnPosition = reply.readInt(); + IBulkCursor bulkCursor = BulkCursorNative.asInterface(reply.readStrongBinder()); if (bulkCursor != null) { - adaptor.set(bulkCursor, rowCount, idColumnPosition); + int rowCount = reply.readInt(); + int idColumnPosition = reply.readInt(); + adaptor.initialize(bulkCursor, rowCount, idColumnPosition); + } else { + adaptor.close(); + adaptor = null; } + return adaptor; + } catch (RemoteException ex) { + adaptor.close(); + throw ex; + } catch (RuntimeException ex) { + adaptor.close(); + throw ex; + } finally { + data.recycle(); + reply.recycle(); } + } finally { + // We close the window now because the cursor adaptor does not + // take ownership of the window until the first call to onMove. + // The adaptor will obtain a fresh reference to the window when + // it is filled. + window.close(); } - - data.recycle(); - reply.recycle(); - - return bulkCursor; - } - - public IBulkCursor bulkQuery(Uri url, String[] projection, - String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, - CursorWindow window) throws RemoteException { - return bulkQueryInternal( - url, projection, selection, selectionArgs, sortOrder, - observer, window, - null /* BulkCursorToCursorAdaptor */); - } - - public Cursor query(Uri url, String[] projection, String selection, - String[] selectionArgs, String sortOrder) throws RemoteException { - //TODO make a pool of windows so we can reuse memory dealers - CursorWindow window = new CursorWindow(false /* window will be used remotely */); - BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); - IBulkCursor bulkCursor = bulkQueryInternal( - url, projection, selection, selectionArgs, sortOrder, - adaptor.getObserver(), window, - adaptor); - if (bulkCursor == null) { - return null; - } - return adaptor; } public String getType(Uri url) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - - mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - String out = reply.readString(); + url.writeToParcel(data, 0); - data.recycle(); - reply.recycle(); + mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0); - return out; + DatabaseUtils.readExceptionFromParcel(reply); + String out = reply.readString(); + return out; + } finally { + data.recycle(); + reply.recycle(); + } } public Uri insert(Uri url, ContentValues values) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - values.writeToParcel(data, 0); - - mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - Uri out = Uri.CREATOR.createFromParcel(reply); + url.writeToParcel(data, 0); + values.writeToParcel(data, 0); - data.recycle(); - reply.recycle(); + mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0); - return out; + DatabaseUtils.readExceptionFromParcel(reply); + Uri out = Uri.CREATOR.createFromParcel(reply); + return out; + } finally { + data.recycle(); + reply.recycle(); + } } public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - data.writeTypedArray(values, 0); - - mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - int count = reply.readInt(); + url.writeToParcel(data, 0); + data.writeTypedArray(values, 0); - data.recycle(); - reply.recycle(); + mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0); - return count; + DatabaseUtils.readExceptionFromParcel(reply); + int count = reply.readInt(); + return count; + } finally { + data.recycle(); + reply.recycle(); + } } public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws RemoteException, OperationApplicationException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IContentProvider.descriptor); - data.writeInt(operations.size()); - for (ContentProviderOperation operation : operations) { - operation.writeToParcel(data, 0); + try { + data.writeInterfaceToken(IContentProvider.descriptor); + data.writeInt(operations.size()); + for (ContentProviderOperation operation : operations) { + operation.writeToParcel(data, 0); + } + mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0); + + DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply); + final ContentProviderResult[] results = + reply.createTypedArray(ContentProviderResult.CREATOR); + return results; + } finally { + data.recycle(); + reply.recycle(); } - mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply); - final ContentProviderResult[] results = - reply.createTypedArray(ContentProviderResult.CREATOR); - - data.recycle(); - reply.recycle(); - - return results; } public int delete(Uri url, String selection, String[] selectionArgs) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - data.writeString(selection); - data.writeStringArray(selectionArgs); - - mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - int count = reply.readInt(); + url.writeToParcel(data, 0); + data.writeString(selection); + data.writeStringArray(selectionArgs); - data.recycle(); - reply.recycle(); + mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0); - return count; + DatabaseUtils.readExceptionFromParcel(reply); + int count = reply.readInt(); + return count; + } finally { + data.recycle(); + reply.recycle(); + } } public int update(Uri url, ContentValues values, String selection, String[] selectionArgs) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - values.writeToParcel(data, 0); - data.writeString(selection); - data.writeStringArray(selectionArgs); - - mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - int count = reply.readInt(); + url.writeToParcel(data, 0); + values.writeToParcel(data, 0); + data.writeString(selection); + data.writeStringArray(selectionArgs); - data.recycle(); - reply.recycle(); + mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0); - return count; + DatabaseUtils.readExceptionFromParcel(reply); + int count = reply.readInt(); + return count; + } finally { + data.recycle(); + reply.recycle(); + } } public ParcelFileDescriptor openFile(Uri url, String mode) throws RemoteException, FileNotFoundException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - data.writeString(mode); - - mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); - int has = reply.readInt(); - ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null; + url.writeToParcel(data, 0); + data.writeString(mode); - data.recycle(); - reply.recycle(); + mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0); - return fd; + DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); + int has = reply.readInt(); + ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null; + return fd; + } finally { + data.recycle(); + reply.recycle(); + } } public AssetFileDescriptor openAssetFile(Uri url, String mode) throws RemoteException, FileNotFoundException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - data.writeString(mode); - - mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); - int has = reply.readInt(); - AssetFileDescriptor fd = has != 0 - ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; + url.writeToParcel(data, 0); + data.writeString(mode); - data.recycle(); - reply.recycle(); + mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0); - return fd; + DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); + int has = reply.readInt(); + AssetFileDescriptor fd = has != 0 + ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; + return fd; + } finally { + data.recycle(); + reply.recycle(); + } } public Bundle call(String method, String request, Bundle args) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); - data.writeInterfaceToken(IContentProvider.descriptor); - - data.writeString(method); - data.writeString(request); - data.writeBundle(args); - - mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - Bundle bundle = reply.readBundle(); + data.writeString(method); + data.writeString(request); + data.writeBundle(args); - data.recycle(); - reply.recycle(); + mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0); - return bundle; + DatabaseUtils.readExceptionFromParcel(reply); + Bundle bundle = reply.readBundle(); + return bundle; + } finally { + data.recycle(); + reply.recycle(); + } } public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - data.writeString(mimeTypeFilter); - - mRemote.transact(IContentProvider.GET_STREAM_TYPES_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - String[] out = reply.createStringArray(); + url.writeToParcel(data, 0); + data.writeString(mimeTypeFilter); - data.recycle(); - reply.recycle(); + mRemote.transact(IContentProvider.GET_STREAM_TYPES_TRANSACTION, data, reply, 0); - return out; + DatabaseUtils.readExceptionFromParcel(reply); + String[] out = reply.createStringArray(); + return out; + } finally { + data.recycle(); + reply.recycle(); + } } public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts) throws RemoteException, FileNotFoundException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - data.writeString(mimeType); - data.writeBundle(opts); - - mRemote.transact(IContentProvider.OPEN_TYPED_ASSET_FILE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); - int has = reply.readInt(); - AssetFileDescriptor fd = has != 0 - ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; - - data.recycle(); - reply.recycle(); - - return fd; + try { + data.writeInterfaceToken(IContentProvider.descriptor); + + url.writeToParcel(data, 0); + data.writeString(mimeType); + data.writeBundle(opts); + + mRemote.transact(IContentProvider.OPEN_TYPED_ASSET_FILE_TRANSACTION, data, reply, 0); + + DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); + int has = reply.readInt(); + AssetFileDescriptor fd = has != 0 + ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; + return fd; + } finally { + data.recycle(); + reply.recycle(); + } } private IBinder mRemote; diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 1e720929bbf4..0d25926265fc 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -16,6 +16,8 @@ package android.content; +import dalvik.system.CloseGuard; + import android.accounts.Account; import android.app.ActivityManagerNative; import android.app.ActivityThread; @@ -33,6 +35,7 @@ import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.StrictMode; import android.os.SystemClock; import android.text.TextUtils; import android.util.EventLog; @@ -1562,27 +1565,39 @@ public abstract class ContentResolver { private final class CursorWrapperInner extends CursorWrapper { private final IContentProvider mContentProvider; public static final String TAG="CursorWrapperInner"; - private boolean mCloseFlag = false; + + private final CloseGuard mCloseGuard = CloseGuard.get(); + private boolean mProviderReleased; CursorWrapperInner(Cursor cursor, IContentProvider icp) { super(cursor); mContentProvider = icp; + mCloseGuard.open("close"); } @Override public void close() { super.close(); ContentResolver.this.releaseProvider(mContentProvider); - mCloseFlag = true; + mProviderReleased = true; + + if (mCloseGuard != null) { + mCloseGuard.close(); + } } @Override protected void finalize() throws Throwable { - // TODO: integrate CloseGuard support. try { - if(!mCloseFlag) { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + + if (!mProviderReleased && mContentProvider != null) { + // Even though we are using CloseGuard, log this anyway so that + // application developers always see the message in the log. Log.w(TAG, "Cursor finalized without prior close()"); - close(); + ContentResolver.this.releaseProvider(mContentProvider); } } finally { super.finalize(); diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java index 72bc9c2f69f9..2a67ff8dac54 100644 --- a/core/java/android/content/IContentProvider.java +++ b/core/java/android/content/IContentProvider.java @@ -18,9 +18,6 @@ package android.content; import android.content.res.AssetFileDescriptor; import android.database.Cursor; -import android.database.CursorWindow; -import android.database.IBulkCursor; -import android.database.IContentObserver; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; @@ -36,13 +33,6 @@ import java.util.ArrayList; * @hide */ public interface IContentProvider extends IInterface { - /** - * @hide - hide this because return type IBulkCursor and parameter - * IContentObserver are system private classes. - */ - public IBulkCursor bulkQuery(Uri url, String[] projection, - String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, - CursorWindow window) throws RemoteException; public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder) throws RemoteException; public String getType(Uri url) throws RemoteException; diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index a3bcc287e021..decb974bded8 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -362,4 +362,6 @@ interface IPackageManager { void verifyPendingInstall(int id, int verificationCode); VerifierDeviceIdentity getVerifierDeviceIdentity(); + + boolean isFirstBoot(); } diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java index 3f23b8900c5f..ee6aec6f0d2d 100644 --- a/core/java/android/database/AbstractCursor.java +++ b/core/java/android/database/AbstractCursor.java @@ -78,13 +78,11 @@ public abstract class AbstractCursor implements CrossProcessCursor { } public void deactivate() { - deactivateInternal(); + onDeactivateOrClose(); } - /** - * @hide - */ - public void deactivateInternal() { + /** @hide */ + protected void onDeactivateOrClose() { if (mSelfObserver != null) { mContentResolver.unregisterContentObserver(mSelfObserver); mSelfObserverRegistered = false; @@ -108,7 +106,7 @@ public abstract class AbstractCursor implements CrossProcessCursor { public void close() { mClosed = true; mContentObservable.unregisterAll(); - deactivateInternal(); + onDeactivateOrClose(); } /** diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java index bfc8123e07fd..5836265c4945 100644 --- a/core/java/android/database/AbstractWindowedCursor.java +++ b/core/java/android/database/AbstractWindowedCursor.java @@ -19,6 +19,11 @@ package android.database; /** * A base class for Cursors that store their data in {@link CursorWindow}s. * <p> + * The cursor owns the cursor window it uses. When the cursor is closed, + * its window is also closed. Likewise, when the window used by the cursor is + * changed, its old window is closed. This policy of strict ownership ensures + * that cursor windows are not leaked. + * </p><p> * Subclasses are responsible for filling the cursor window with data during * {@link #onMove(int, int)}, allocating a new cursor window if necessary. * During {@link #requery()}, the existing cursor window should be cleared and @@ -180,4 +185,25 @@ public abstract class AbstractWindowedCursor extends AbstractCursor { mWindow = null; } } + + /** + * If there is a window, clear it. + * Otherwise, creates a local window. + * @hide + */ + protected void clearOrCreateLocalWindow() { + if (mWindow == null) { + // If there isn't a window set already it will only be accessed locally + mWindow = new CursorWindow(true /* the window is local only */); + } else { + mWindow.clear(); + } + } + + /** @hide */ + @Override + protected void onDeactivateOrClose() { + super.onDeactivateOrClose(); + closeWindow(); + } } diff --git a/core/java/android/database/BulkCursorNative.java b/core/java/android/database/BulkCursorNative.java index fa62d6921778..4fada8c2fd29 100644 --- a/core/java/android/database/BulkCursorNative.java +++ b/core/java/android/database/BulkCursorNative.java @@ -20,12 +20,13 @@ import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; /** * Native implementation of the bulk cursor. This is only for use in implementing * IPC, application code should use the Cursor interface. - * + * * {@hide} */ public abstract class BulkCursorNative extends Binder implements IBulkCursor @@ -61,13 +62,13 @@ public abstract class BulkCursorNative extends Binder implements IBulkCursor data.enforceInterface(IBulkCursor.descriptor); int startPos = data.readInt(); CursorWindow window = getWindow(startPos); + reply.writeNoException(); if (window == null) { reply.writeInt(0); - return true; + } else { + reply.writeInt(1); + window.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } - reply.writeNoException(); - reply.writeInt(1); - window.writeToParcel(reply, 0); return true; } @@ -184,172 +185,172 @@ final class BulkCursorProxy implements IBulkCursor { { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IBulkCursor.descriptor); + data.writeInt(startPos); - data.writeInterfaceToken(IBulkCursor.descriptor); - - data.writeInt(startPos); - - mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0); + mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0); + DatabaseUtils.readExceptionFromParcel(reply); - DatabaseUtils.readExceptionFromParcel(reply); - - CursorWindow window = null; - if (reply.readInt() == 1) { - window = CursorWindow.newFromParcel(reply); + CursorWindow window = null; + if (reply.readInt() == 1) { + window = CursorWindow.newFromParcel(reply); + } + return window; + } finally { + data.recycle(); + reply.recycle(); } - - data.recycle(); - reply.recycle(); - - return window; } public void onMove(int position) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IBulkCursor.descriptor); + data.writeInt(position); - data.writeInterfaceToken(IBulkCursor.descriptor); - - data.writeInt(position); - - mRemote.transact(ON_MOVE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - data.recycle(); - reply.recycle(); + mRemote.transact(ON_MOVE_TRANSACTION, data, reply, 0); + DatabaseUtils.readExceptionFromParcel(reply); + } finally { + data.recycle(); + reply.recycle(); + } } public int count() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IBulkCursor.descriptor); - data.writeInterfaceToken(IBulkCursor.descriptor); - - boolean result = mRemote.transact(COUNT_TRANSACTION, data, reply, 0); + boolean result = mRemote.transact(COUNT_TRANSACTION, data, reply, 0); + DatabaseUtils.readExceptionFromParcel(reply); - DatabaseUtils.readExceptionFromParcel(reply); - - int count; - if (result == false) { - count = -1; - } else { - count = reply.readInt(); + int count; + if (result == false) { + count = -1; + } else { + count = reply.readInt(); + } + return count; + } finally { + data.recycle(); + reply.recycle(); } - data.recycle(); - reply.recycle(); - return count; } public String[] getColumnNames() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IBulkCursor.descriptor); - data.writeInterfaceToken(IBulkCursor.descriptor); - - mRemote.transact(GET_COLUMN_NAMES_TRANSACTION, data, reply, 0); + mRemote.transact(GET_COLUMN_NAMES_TRANSACTION, data, reply, 0); + DatabaseUtils.readExceptionFromParcel(reply); - DatabaseUtils.readExceptionFromParcel(reply); - - String[] columnNames = null; - int numColumns = reply.readInt(); - columnNames = new String[numColumns]; - for (int i = 0; i < numColumns; i++) { - columnNames[i] = reply.readString(); + String[] columnNames = null; + int numColumns = reply.readInt(); + columnNames = new String[numColumns]; + for (int i = 0; i < numColumns; i++) { + columnNames[i] = reply.readString(); + } + return columnNames; + } finally { + data.recycle(); + reply.recycle(); } - - data.recycle(); - reply.recycle(); - return columnNames; } public void deactivate() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IBulkCursor.descriptor); - data.writeInterfaceToken(IBulkCursor.descriptor); - - mRemote.transact(DEACTIVATE_TRANSACTION, data, reply, 0); - DatabaseUtils.readExceptionFromParcel(reply); - - data.recycle(); - reply.recycle(); + mRemote.transact(DEACTIVATE_TRANSACTION, data, reply, 0); + DatabaseUtils.readExceptionFromParcel(reply); + } finally { + data.recycle(); + reply.recycle(); + } } public void close() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IBulkCursor.descriptor); - data.writeInterfaceToken(IBulkCursor.descriptor); - - mRemote.transact(CLOSE_TRANSACTION, data, reply, 0); - DatabaseUtils.readExceptionFromParcel(reply); - - data.recycle(); - reply.recycle(); + mRemote.transact(CLOSE_TRANSACTION, data, reply, 0); + DatabaseUtils.readExceptionFromParcel(reply); + } finally { + data.recycle(); + reply.recycle(); + } } public int requery(IContentObserver observer, CursorWindow window) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IBulkCursor.descriptor); + data.writeStrongInterface(observer); + window.writeToParcel(data, 0); - data.writeInterfaceToken(IBulkCursor.descriptor); - - data.writeStrongInterface(observer); - window.writeToParcel(data, 0); - - boolean result = mRemote.transact(REQUERY_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); + boolean result = mRemote.transact(REQUERY_TRANSACTION, data, reply, 0); + DatabaseUtils.readExceptionFromParcel(reply); - int count; - if (!result) { - count = -1; - } else { - count = reply.readInt(); - mExtras = reply.readBundle(); + int count; + if (!result) { + count = -1; + } else { + count = reply.readInt(); + mExtras = reply.readBundle(); + } + return count; + } finally { + data.recycle(); + reply.recycle(); } - - data.recycle(); - reply.recycle(); - - return count; } public boolean getWantsAllOnMoveCalls() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IBulkCursor.descriptor); - data.writeInterfaceToken(IBulkCursor.descriptor); - - mRemote.transact(WANTS_ON_MOVE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); + mRemote.transact(WANTS_ON_MOVE_TRANSACTION, data, reply, 0); + DatabaseUtils.readExceptionFromParcel(reply); - int result = reply.readInt(); - data.recycle(); - reply.recycle(); - return result != 0; + int result = reply.readInt(); + return result != 0; + } finally { + data.recycle(); + reply.recycle(); + } } public Bundle getExtras() throws RemoteException { if (mExtras == null) { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IBulkCursor.descriptor); - data.writeInterfaceToken(IBulkCursor.descriptor); + mRemote.transact(GET_EXTRAS_TRANSACTION, data, reply, 0); + DatabaseUtils.readExceptionFromParcel(reply); - mRemote.transact(GET_EXTRAS_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - mExtras = reply.readBundle(); - data.recycle(); - reply.recycle(); + mExtras = reply.readBundle(); + } finally { + data.recycle(); + reply.recycle(); + } } return mExtras; } @@ -357,19 +358,19 @@ final class BulkCursorProxy implements IBulkCursor { public Bundle respond(Bundle extras) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IBulkCursor.descriptor); + data.writeBundle(extras); - data.writeInterfaceToken(IBulkCursor.descriptor); - - data.writeBundle(extras); - - mRemote.transact(RESPOND_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); + mRemote.transact(RESPOND_TRANSACTION, data, reply, 0); + DatabaseUtils.readExceptionFromParcel(reply); - Bundle returnExtras = reply.readBundle(); - data.recycle(); - reply.recycle(); - return returnExtras; + Bundle returnExtras = reply.readBundle(); + return returnExtras; + } finally { + data.recycle(); + reply.recycle(); + } } } diff --git a/core/java/android/database/BulkCursorToCursorAdaptor.java b/core/java/android/database/BulkCursorToCursorAdaptor.java index 9c1b26d0a648..cbdd07fb29d3 100644 --- a/core/java/android/database/BulkCursorToCursorAdaptor.java +++ b/core/java/android/database/BulkCursorToCursorAdaptor.java @@ -21,40 +21,24 @@ import android.os.RemoteException; import android.util.Log; /** - * Adapts an {@link IBulkCursor} to a {@link Cursor} for use in the local - * process. + * Adapts an {@link IBulkCursor} to a {@link Cursor} for use in the local process. * * {@hide} */ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor { private static final String TAG = "BulkCursor"; - private SelfContentObserver mObserverBridge; + private SelfContentObserver mObserverBridge = new SelfContentObserver(this); private IBulkCursor mBulkCursor; private int mCount; private String[] mColumns; private boolean mWantsAllOnMoveCalls; - public void set(IBulkCursor bulkCursor) { - mBulkCursor = bulkCursor; - - try { - mCount = mBulkCursor.count(); - mWantsAllOnMoveCalls = mBulkCursor.getWantsAllOnMoveCalls(); - - // Search for the rowID column index and set it for our parent - mColumns = mBulkCursor.getColumnNames(); - mRowIdColumnIndex = findRowIdColumnIndex(mColumns); - } catch (RemoteException ex) { - Log.e(TAG, "Setup failed because the remote process is dead"); - } - } - /** - * Version of set() that does fewer Binder calls if the caller - * already knows BulkCursorToCursorAdaptor's properties. + * Initializes the adaptor. + * Must be called before first use. */ - public void set(IBulkCursor bulkCursor, int count, int idIndex) { + public void initialize(IBulkCursor bulkCursor, int count, int idIndex) { mBulkCursor = bulkCursor; mColumns = null; // lazily retrieved mCount = count; @@ -80,31 +64,37 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor { * * @return A SelfContentObserver hooked up to this Cursor */ - public synchronized IContentObserver getObserver() { - if (mObserverBridge == null) { - mObserverBridge = new SelfContentObserver(this); - } + public IContentObserver getObserver() { return mObserverBridge.getContentObserver(); } + private void throwIfCursorIsClosed() { + if (mBulkCursor == null) { + throw new StaleDataException("Attempted to access a cursor after it has been closed."); + } + } + @Override public int getCount() { + throwIfCursorIsClosed(); return mCount; } @Override public boolean onMove(int oldPosition, int newPosition) { + throwIfCursorIsClosed(); + try { // Make sure we have the proper window if (mWindow != null) { if (newPosition < mWindow.getStartPosition() || newPosition >= (mWindow.getStartPosition() + mWindow.getNumRows())) { - mWindow = mBulkCursor.getWindow(newPosition); + setWindow(mBulkCursor.getWindow(newPosition)); } else if (mWantsAllOnMoveCalls) { mBulkCursor.onMove(newPosition); } } else { - mWindow = mBulkCursor.getWindow(newPosition); + setWindow(mBulkCursor.getWindow(newPosition)); } } catch (RemoteException ex) { // We tried to get a window and failed @@ -126,44 +116,54 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor { // which is what actually makes the data set invalid. super.deactivate(); - try { - mBulkCursor.deactivate(); - } catch (RemoteException ex) { - Log.w(TAG, "Remote process exception when deactivating"); + if (mBulkCursor != null) { + try { + mBulkCursor.deactivate(); + } catch (RemoteException ex) { + Log.w(TAG, "Remote process exception when deactivating"); + } } - mWindow = null; } @Override public void close() { super.close(); - try { - mBulkCursor.close(); - } catch (RemoteException ex) { - Log.w(TAG, "Remote process exception when closing"); + + if (mBulkCursor != null) { + try { + mBulkCursor.close(); + } catch (RemoteException ex) { + Log.w(TAG, "Remote process exception when closing"); + } finally { + mBulkCursor = null; + } } - mWindow = null; } @Override public boolean requery() { + throwIfCursorIsClosed(); + try { - int oldCount = mCount; - //TODO get the window from a pool somewhere to avoid creating the memory dealer - mCount = mBulkCursor.requery(getObserver(), new CursorWindow( - false /* the window will be accessed across processes */)); - if (mCount != -1) { - mPos = -1; - closeWindow(); - - // super.requery() will call onChanged. Do it here instead of relying on the - // observer from the far side so that observers can see a correct value for mCount - // when responding to onChanged. - super.requery(); - return true; - } else { - deactivate(); - return false; + CursorWindow newWindow = new CursorWindow(false /* create a remote window */); + try { + mCount = mBulkCursor.requery(getObserver(), newWindow); + if (mCount != -1) { + mPos = -1; + closeWindow(); + + // super.requery() will call onChanged. Do it here instead of relying on the + // observer from the far side so that observers can see a correct value for mCount + // when responding to onChanged. + super.requery(); + return true; + } else { + deactivate(); + return false; + } + } finally { + // Don't take ownership of the window until the next call to onMove. + newWindow.close(); } } catch (Exception ex) { Log.e(TAG, "Unable to requery because the remote process exception " + ex.getMessage()); @@ -174,6 +174,8 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor { @Override public String[] getColumnNames() { + throwIfCursorIsClosed(); + if (mColumns == null) { try { mColumns = mBulkCursor.getColumnNames(); @@ -187,6 +189,8 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor { @Override public Bundle getExtras() { + throwIfCursorIsClosed(); + try { return mBulkCursor.getExtras(); } catch (RemoteException e) { @@ -198,6 +202,8 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor { @Override public Bundle respond(Bundle extras) { + throwIfCursorIsClosed(); + try { return mBulkCursor.respond(extras); } catch (RemoteException e) { diff --git a/core/java/android/database/CrossProcessCursor.java b/core/java/android/database/CrossProcessCursor.java index 77ba3a54463a..8e6a5aa01598 100644 --- a/core/java/android/database/CrossProcessCursor.java +++ b/core/java/android/database/CrossProcessCursor.java @@ -16,7 +16,7 @@ package android.database; -public interface CrossProcessCursor extends Cursor{ +public interface CrossProcessCursor extends Cursor { /** * returns a pre-filled window, return NULL if no such window */ diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java index 8fa4d3b5414d..a65b3b304558 100644 --- a/core/java/android/database/CursorToBulkCursorAdaptor.java +++ b/core/java/android/database/CursorToBulkCursorAdaptor.java @@ -24,19 +24,37 @@ import android.util.Log; /** * Wraps a BulkCursor around an existing Cursor making it remotable. + * <p> + * If the wrapped cursor is a {@link AbstractWindowedCursor} then it owns + * the cursor window. Otherwise, the adaptor takes ownership of the + * cursor itself and ensures it gets closed as needed during deactivation + * and requeries. + * </p> * * {@hide} */ public final class CursorToBulkCursorAdaptor extends BulkCursorNative implements IBinder.DeathRecipient { private static final String TAG = "Cursor"; - private final CrossProcessCursor mCursor; - private CursorWindow mWindow; + + private final Object mLock = new Object(); private final String mProviderName; private ContentObserverProxy mObserver; - private static final class ContentObserverProxy extends ContentObserver - { + /** + * The cursor that is being adapted. + * This field is set to null when the cursor is closed. + */ + private CrossProcessCursor mCursor; + + /** + * The cursor window used by the cross process cursor. + * This field is always null for abstract windowed cursors since they are responsible + * for managing the lifetime of their window. + */ + private CursorWindow mWindowForNonWindowedCursor; + + private static final class ContentObserverProxy extends ContentObserver { protected IContentObserver mRemote; public ContentObserverProxy(IContentObserver remoteObserver, DeathRecipient recipient) { @@ -70,7 +88,7 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative } public CursorToBulkCursorAdaptor(Cursor cursor, IContentObserver observer, String providerName, - boolean allowWrite, CursorWindow window) { + CursorWindow window) { try { mCursor = (CrossProcessCursor) cursor; if (mCursor instanceof AbstractWindowedCursor) { @@ -81,90 +99,167 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative + providerName, new RuntimeException()); } } - windowedCursor.setWindow(window); + windowedCursor.setWindow(window); // cursor takes ownership of window } else { - mWindow = window; + mWindowForNonWindowedCursor = window; // we own the window mCursor.fillWindow(0, window); } } catch (ClassCastException e) { // TODO Implement this case. + window.close(); throw new UnsupportedOperationException( "Only CrossProcessCursor cursors are supported across process for now", e); } mProviderName = providerName; - createAndRegisterObserverProxy(observer); + synchronized (mLock) { + createAndRegisterObserverProxyLocked(observer); + } } - + + private void closeCursorAndWindowLocked() { + if (mCursor != null) { + unregisterObserverProxyLocked(); + mCursor.close(); + mCursor = null; + } + + if (mWindowForNonWindowedCursor != null) { + mWindowForNonWindowedCursor.close(); + mWindowForNonWindowedCursor = null; + } + } + + private void throwIfCursorIsClosed() { + if (mCursor == null) { + throw new StaleDataException("Attempted to access a cursor after it has been closed."); + } + } + + @Override public void binderDied() { - mCursor.close(); - if (mWindow != null) { - mWindow.close(); + synchronized (mLock) { + closeCursorAndWindowLocked(); } } - + + @Override public CursorWindow getWindow(int startPos) { - mCursor.moveToPosition(startPos); - - if (mWindow != null) { - if (startPos < mWindow.getStartPosition() || - startPos >= (mWindow.getStartPosition() + mWindow.getNumRows())) { - mCursor.fillWindow(startPos, mWindow); - } - return mWindow; - } else { - return ((AbstractWindowedCursor)mCursor).getWindow(); + synchronized (mLock) { + throwIfCursorIsClosed(); + + mCursor.moveToPosition(startPos); + + final CursorWindow window; + if (mCursor instanceof AbstractWindowedCursor) { + window = ((AbstractWindowedCursor)mCursor).getWindow(); + } else { + window = mWindowForNonWindowedCursor; + if (window != null + && (startPos < window.getStartPosition() || + startPos >= (window.getStartPosition() + window.getNumRows()))) { + mCursor.fillWindow(startPos, window); + } + } + + // Acquire a reference before returning from this RPC. + // The Binder proxy will decrement the reference count again as part of writing + // the CursorWindow to the reply parcel as a return value. + if (window != null) { + window.acquireReference(); + } + return window; } } + @Override public void onMove(int position) { - mCursor.onMove(mCursor.getPosition(), position); + synchronized (mLock) { + throwIfCursorIsClosed(); + + mCursor.onMove(mCursor.getPosition(), position); + } } + @Override public int count() { - return mCursor.getCount(); + synchronized (mLock) { + throwIfCursorIsClosed(); + + return mCursor.getCount(); + } } + @Override public String[] getColumnNames() { - return mCursor.getColumnNames(); + synchronized (mLock) { + throwIfCursorIsClosed(); + + return mCursor.getColumnNames(); + } } + @Override public void deactivate() { - maybeUnregisterObserverProxy(); - mCursor.deactivate(); + synchronized (mLock) { + if (mCursor != null) { + unregisterObserverProxyLocked(); + mCursor.deactivate(); + } + } } + @Override public void close() { - maybeUnregisterObserverProxy(); - mCursor.close(); + synchronized (mLock) { + closeCursorAndWindowLocked(); + } } + @Override public int requery(IContentObserver observer, CursorWindow window) { - if (mWindow == null) { - ((AbstractWindowedCursor)mCursor).setWindow(window); - } - try { - if (!mCursor.requery()) { - return -1; + synchronized (mLock) { + throwIfCursorIsClosed(); + + if (mCursor instanceof AbstractWindowedCursor) { + ((AbstractWindowedCursor) mCursor).setWindow(window); + } else { + if (mWindowForNonWindowedCursor != null) { + mWindowForNonWindowedCursor.close(); + } + mWindowForNonWindowedCursor = window; } - } catch (IllegalStateException e) { - IllegalStateException leakProgram = new IllegalStateException( - mProviderName + " Requery misuse db, mCursor isClosed:" + - mCursor.isClosed(), e); - throw leakProgram; - } - - if (mWindow != null) { - mCursor.fillWindow(0, window); - mWindow = window; + + try { + if (!mCursor.requery()) { + return -1; + } + } catch (IllegalStateException e) { + IllegalStateException leakProgram = new IllegalStateException( + mProviderName + " Requery misuse db, mCursor isClosed:" + + mCursor.isClosed(), e); + throw leakProgram; + } + + if (!(mCursor instanceof AbstractWindowedCursor)) { + if (window != null) { + mCursor.fillWindow(0, window); + } + } + + unregisterObserverProxyLocked(); + createAndRegisterObserverProxyLocked(observer); + return mCursor.getCount(); } - maybeUnregisterObserverProxy(); - createAndRegisterObserverProxy(observer); - return mCursor.getCount(); } + @Override public boolean getWantsAllOnMoveCalls() { - return mCursor.getWantsAllOnMoveCalls(); + synchronized (mLock) { + throwIfCursorIsClosed(); + + return mCursor.getWantsAllOnMoveCalls(); + } } /** @@ -173,7 +268,7 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative * @param observer the IContentObserver that wants to monitor the cursor * @throws IllegalStateException if an observer is already registered */ - private void createAndRegisterObserverProxy(IContentObserver observer) { + private void createAndRegisterObserverProxyLocked(IContentObserver observer) { if (mObserver != null) { throw new IllegalStateException("an observer is already registered"); } @@ -182,7 +277,7 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative } /** Unregister the observer if it is already registered. */ - private void maybeUnregisterObserverProxy() { + private void unregisterObserverProxyLocked() { if (mObserver != null) { mCursor.unregisterContentObserver(mObserver); mObserver.unlinkToDeath(this); @@ -190,11 +285,21 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative } } + @Override public Bundle getExtras() { - return mCursor.getExtras(); + synchronized (mLock) { + throwIfCursorIsClosed(); + + return mCursor.getExtras(); + } } + @Override public Bundle respond(Bundle extras) { - return mCursor.respond(extras); + synchronized (mLock) { + throwIfCursorIsClosed(); + + return mCursor.respond(extras); + } } } diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java index 2e3ef286fe80..5a91b80034e4 100644 --- a/core/java/android/database/CursorWindow.java +++ b/core/java/android/database/CursorWindow.java @@ -16,6 +16,8 @@ package android.database; +import dalvik.system.CloseGuard; + import android.content.res.Resources; import android.database.sqlite.SQLiteClosable; import android.database.sqlite.SQLiteException; @@ -48,6 +50,8 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { private int mStartPos; + private final CloseGuard mCloseGuard = CloseGuard.get(); + private static native int nativeInitializeEmpty(int cursorWindowSize, boolean localOnly); private static native int nativeInitializeFromBinder(IBinder nativeBinder); private static native void nativeDispose(int windowPtr); @@ -91,6 +95,7 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { throw new CursorWindowAllocationException("Cursor window allocation of " + (sCursorWindowSize / 1024) + " kb failed. " + printStats()); } + mCloseGuard.open("close"); recordNewWindow(Binder.getCallingPid(), mWindowPtr); } @@ -102,11 +107,15 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { throw new CursorWindowAllocationException("Cursor window could not be " + "created from binder."); } + mCloseGuard.open("close"); } @Override protected void finalize() throws Throwable { try { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } dispose(); } finally { super.finalize(); @@ -114,6 +123,9 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { } private void dispose() { + if (mCloseGuard != null) { + mCloseGuard.close(); + } if (mWindowPtr != 0) { recordClosingOfWindow(mWindowPtr); nativeDispose(mWindowPtr); @@ -677,6 +689,10 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeStrongBinder(nativeGetBinder(mWindowPtr)); dest.writeInt(mStartPos); + + if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { + releaseReference(); + } } @Override diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java index 81fe8241106a..9d7e15201be5 100644 --- a/core/java/android/database/sqlite/SQLiteCursor.java +++ b/core/java/android/database/sqlite/SQLiteCursor.java @@ -89,8 +89,6 @@ public class SQLiteCursor extends AbstractWindowedCursor { * @param query the {@link SQLiteQuery} object associated with this cursor object. */ public SQLiteCursor(SQLiteCursorDriver driver, String editTable, SQLiteQuery query) { - // The AbstractCursor constructor needs to do some setup. - super(); if (query == null) { throw new IllegalArgumentException("query object cannot be null"); } @@ -157,12 +155,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { } private void fillWindow(int startPos) { - if (mWindow == null) { - // If there isn't a window set already it will only be accessed locally - mWindow = new CursorWindow(true /* the window is local only */); - } else { - mWindow.clear(); - } + clearOrCreateLocalWindow(); mWindow.setStartPosition(startPos); int count = getQuery().fillWindow(mWindow); if (startPos == 0) { // fillWindow returns count(*) only for startPos = 0 @@ -214,16 +207,9 @@ public class SQLiteCursor extends AbstractWindowedCursor { return mColumns; } - private void deactivateCommon() { - if (false) Log.v(TAG, "<<< Releasing cursor " + this); - closeWindow(); - if (false) Log.v("DatabaseWindow", "closing window in release()"); - } - @Override public void deactivate() { super.deactivate(); - deactivateCommon(); mDriver.cursorDeactivated(); } @@ -231,7 +217,6 @@ public class SQLiteCursor extends AbstractWindowedCursor { public void close() { super.close(); synchronized (this) { - deactivateCommon(); mQuery.close(); mDriver.cursorClosed(); } diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index aaad8a1c7a98..1b24f0c7b35f 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -40,6 +40,8 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> { public long limitBytes; public long lastSnooze; + private static final long DEFAULT_MTU = 1500; + public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes, long limitBytes, long lastSnooze) { this.template = checkNotNull(template, "missing NetworkTemplate"); @@ -71,6 +73,17 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> { return 0; } + /** + * Test if given measurement is near enough to {@link #limitBytes} to be + * considered over-limit. + */ + public boolean isOverLimit(long totalBytes) { + // over-estimate, since kernel will trigger limit once first packet + // trips over limit. + totalBytes += 2 * DEFAULT_MTU; + return limitBytes != LIMIT_DISABLED && totalBytes >= limitBytes; + } + /** {@inheritDoc} */ public int compareTo(NetworkPolicy another) { if (another == null || another.limitBytes == LIMIT_DISABLED) { diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index fe0106dc52c4..33310dfd0ad8 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -768,61 +768,6 @@ public final class NfcAdapter { } /** - * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated - * @deprecated use {@link CreateNdefMessageCallback} or {@link OnNdefPushCompleteCallback} - * @hide - */ - @Deprecated - public interface NdefPushCallback { - /** - * @deprecated use {@link CreateNdefMessageCallback} instead - */ - @Deprecated - NdefMessage createMessage(); - /** - * @deprecated use{@link OnNdefPushCompleteCallback} instead - */ - @Deprecated - void onMessagePushed(); - } - - /** - * TODO: Remove this - * Converts new callbacks to old callbacks. - */ - static final class LegacyCallbackWrapper implements CreateNdefMessageCallback, - OnNdefPushCompleteCallback { - final NdefPushCallback mLegacyCallback; - LegacyCallbackWrapper(NdefPushCallback legacyCallback) { - mLegacyCallback = legacyCallback; - } - @Override - public void onNdefPushComplete(NfcEvent event) { - mLegacyCallback.onMessagePushed(); - } - @Override - public NdefMessage createNdefMessage(NfcEvent event) { - return mLegacyCallback.createMessage(); - } - } - - /** - * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated - * @deprecated use {@link #setNdefPushMessageCallback} instead - * @hide - */ - @Deprecated - public void enableForegroundNdefPush(Activity activity, final NdefPushCallback callback) { - if (activity == null || callback == null) { - throw new NullPointerException(); - } - enforceResumed(activity); - LegacyCallbackWrapper callbackWrapper = new LegacyCallbackWrapper(callback); - mNfcActivityManager.setNdefPushMessageCallback(activity, callbackWrapper); - mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callbackWrapper); - } - - /** * Enable NDEF Push feature. * <p>This API is for the Settings application. * @hide diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 68385b4b4b71..cc2fa8532d3d 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -35,7 +35,6 @@ import dalvik.system.VMDebug; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -902,6 +901,7 @@ public final class StrictMode { return false; } + // Thread policy controls BlockGuard. int threadPolicyMask = StrictMode.DETECT_DISK_WRITE | StrictMode.DETECT_DISK_READ | StrictMode.DETECT_NETWORK; @@ -915,10 +915,16 @@ public final class StrictMode { StrictMode.setThreadPolicyMask(threadPolicyMask); + // VM Policy controls CloseGuard, detection of Activity leaks, + // and instance counting. if (IS_USER_BUILD) { setCloseGuardEnabled(false); } else { - setVmPolicy(new VmPolicy.Builder().detectAll().penaltyDropBox().build()); + VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll().penaltyDropBox(); + if (IS_ENG_BUILD) { + policyBuilder.penaltyLog(); + } + setVmPolicy(policyBuilder.build()); setCloseGuardEnabled(vmClosableObjectLeaksEnabled()); } return true; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index b972ebc7907e..86be28a534da 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1486,7 +1486,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal | AccessibilityEvent.TYPE_VIEW_FOCUSED | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER - | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT; + | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT + | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED; /** * Temporary Rect currently for use in setBackground(). This will probably diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 25bc559e94e3..86dd9df0cb0a 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -200,15 +200,6 @@ import java.util.List; * <li>{@link #getBeforeText()} - The text of the source before the change.</li> * <li>{@link #getContentDescription()} - The content description of the source.</li> * </ul> - * <em>Note:</em> This event type is not dispatched to descendants though - * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) - * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event - * source {@link android.view.View} and the sub-tree rooted at it will not receive - * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent) - * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add - * text content to such events is by setting the - * {@link android.R.styleable#View_contentDescription contentDescription} of the source - * view.</br> * </p> * <p> * <b>View text selection changed</b> - represents the event of changing the text diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index f46af5137661..6d19c23fd2cb 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2074,7 +2074,8 @@ public class WebView extends AbsoluteLayout * If the value of the encoding parameter is 'base64', then the data must * be encoded as base64. Otherwise, the data must use ASCII encoding for * octets inside the range of safe URL characters and use the standard %xx - * hex encoding of URLs for octets outside that range. + * hex encoding of URLs for octets outside that range. For example, + * '#', '%', '\', '?' should be replaced by %23, %25, %27, %3f respectively. * <p> * The 'data' scheme URL formed by this method uses the default US-ASCII * charset. If you need need to set a different charset, you should form a @@ -7415,6 +7416,10 @@ public class WebView extends AbsoluteLayout } } + void sendPluginDrawMsg() { + mWebViewCore.sendMessage(EventHub.PLUGIN_SURFACE_READY); + } + /** * Returns plugin bounds if x/y in content coordinates corresponds to a * plugin. Otherwise a NULL rectangle is returned. diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 44688b8bd2be..1294a28df190 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -1032,6 +1032,8 @@ public final class WebViewCore { static final int EXECUTE_JS = 194; + static final int PLUGIN_SURFACE_READY = 195; + // private message ids private static final int DESTROY = 200; @@ -1587,6 +1589,10 @@ public final class WebViewCore { nativeFullScreenPluginHidden(msg.arg1); break; + case PLUGIN_SURFACE_READY: + nativePluginSurfaceReady(); + break; + case ADD_PACKAGE_NAMES: if (BrowserFrame.sJavaBridge == null) { throw new IllegalStateException("No WebView " + @@ -2826,6 +2832,7 @@ public final class WebViewCore { private native void nativeResume(); private native void nativeFreeMemory(); private native void nativeFullScreenPluginHidden(int npp); + private native void nativePluginSurfaceReady(); private native boolean nativeValidNodeAndBounds(int frame, int node, Rect bounds); diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index fd19b5fea9d2..e16a8bdff8fa 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -922,15 +922,20 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { if (selectedView != null) { event.setEnabled(selectedView.isEnabled()); } + event.setCurrentItemIndex(getSelectedItemPosition()); event.setFromIndex(getFirstVisiblePosition()); event.setToIndex(getLastVisiblePosition()); event.setItemCount(getAdapter().getCount()); } private boolean isScrollableForAccessibility() { - final int itemCount = getAdapter().getCount(); - return itemCount > 0 - && (getFirstVisiblePosition() > 0 || getLastVisiblePosition() < itemCount - 1); + T adapter = getAdapter(); + if (adapter != null) { + final int itemCount = adapter.getCount(); + return itemCount > 0 + && (getFirstVisiblePosition() > 0 || getLastVisiblePosition() < itemCount - 1); + } + return false; } @Override diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index 62b078fb5df5..510e2d4cb488 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -44,7 +44,6 @@ public class SpellChecker implements SpellCheckerSessionListener { private final static int MAX_SPELL_BATCH_SIZE = 50; private final TextView mTextView; - private final Editable mText; final SpellCheckerSession mSpellCheckerSession; final int mCookie; @@ -64,7 +63,6 @@ public class SpellChecker implements SpellCheckerSessionListener { public SpellChecker(TextView textView) { mTextView = textView; - mText = (Editable) textView.getText(); final TextServicesManager textServicesManager = (TextServicesManager) textView.getContext(). getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE); @@ -121,9 +119,9 @@ public class SpellChecker implements SpellCheckerSessionListener { return mLength - 1; } - private void addSpellCheckSpan(int start, int end) { + private void addSpellCheckSpan(Editable editable, int start, int end) { final int index = nextSpellCheckSpanIndex(); - mText.setSpan(mSpellCheckSpans[index], start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + editable.setSpan(mSpellCheckSpans[index], start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mIds[index] = mSpanSequenceCounter++; } @@ -168,8 +166,9 @@ public class SpellChecker implements SpellCheckerSessionListener { private void spellCheck() { if (mSpellCheckerSession == null) return; - final int selectionStart = Selection.getSelectionStart(mText); - final int selectionEnd = Selection.getSelectionEnd(mText); + Editable editable = (Editable) mTextView.getText(); + final int selectionStart = Selection.getSelectionStart(editable); + final int selectionEnd = Selection.getSelectionEnd(editable); TextInfo[] textInfos = new TextInfo[mLength]; int textInfosCount = 0; @@ -178,12 +177,12 @@ public class SpellChecker implements SpellCheckerSessionListener { final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[i]; if (spellCheckSpan.isSpellCheckInProgress()) continue; - final int start = mText.getSpanStart(spellCheckSpan); - final int end = mText.getSpanEnd(spellCheckSpan); + final int start = editable.getSpanStart(spellCheckSpan); + final int end = editable.getSpanEnd(spellCheckSpan); // Do not check this word if the user is currently editing it if (start >= 0 && end > start && (selectionEnd < start || selectionStart > end)) { - final String word = mText.subSequence(start, end).toString(); + final String word = editable.subSequence(start, end).toString(); spellCheckSpan.setSpellCheckInProgress(true); textInfos[textInfosCount++] = new TextInfo(word, mCookie, mIds[i]); } @@ -202,6 +201,8 @@ public class SpellChecker implements SpellCheckerSessionListener { @Override public void onGetSuggestions(SuggestionsInfo[] results) { + Editable editable = (Editable) mTextView.getText(); + for (int i = 0; i < results.length; i++) { SuggestionsInfo suggestionsInfo = results[i]; if (suggestionsInfo.getCookie() != mCookie) continue; @@ -217,9 +218,9 @@ public class SpellChecker implements SpellCheckerSessionListener { SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j]; if (!isInDictionary && looksLikeTypo) { - createMisspelledSuggestionSpan(suggestionsInfo, spellCheckSpan); + createMisspelledSuggestionSpan(editable, suggestionsInfo, spellCheckSpan); } - mText.removeSpan(spellCheckSpan); + editable.removeSpan(spellCheckSpan); break; } } @@ -234,18 +235,18 @@ public class SpellChecker implements SpellCheckerSessionListener { } } - private void createMisspelledSuggestionSpan(SuggestionsInfo suggestionsInfo, - SpellCheckSpan spellCheckSpan) { - final int start = mText.getSpanStart(spellCheckSpan); - final int end = mText.getSpanEnd(spellCheckSpan); + private void createMisspelledSuggestionSpan(Editable editable, + SuggestionsInfo suggestionsInfo, SpellCheckSpan spellCheckSpan) { + final int start = editable.getSpanStart(spellCheckSpan); + final int end = editable.getSpanEnd(spellCheckSpan); // Other suggestion spans may exist on that region, with identical suggestions, filter // them out to avoid duplicates. First, filter suggestion spans on that exact region. - SuggestionSpan[] suggestionSpans = mText.getSpans(start, end, SuggestionSpan.class); + SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class); final int length = suggestionSpans.length; for (int i = 0; i < length; i++) { - final int spanStart = mText.getSpanStart(suggestionSpans[i]); - final int spanEnd = mText.getSpanEnd(suggestionSpans[i]); + final int spanStart = editable.getSpanStart(suggestionSpans[i]); + final int spanEnd = editable.getSpanEnd(suggestionSpans[i]); if (spanStart != start || spanEnd != end) { suggestionSpans[i] = null; break; @@ -293,7 +294,7 @@ public class SpellChecker implements SpellCheckerSessionListener { SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions, SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED); - mText.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // TODO limit to the word rectangle region mTextView.invalidate(); @@ -304,22 +305,24 @@ public class SpellChecker implements SpellCheckerSessionListener { private Object mRange = new Object(); public void init(int start, int end) { - mText.setSpan(mRange, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ((Editable) mTextView.getText()).setSpan(mRange, start, end, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } public void close() { - mText.removeSpan(mRange); + ((Editable) mTextView.getText()).removeSpan(mRange); } public boolean isDone() { - return mText.getSpanStart(mRange) < 0; + return ((Editable) mTextView.getText()).getSpanStart(mRange) < 0; } public void parse() { + Editable editable = (Editable) mTextView.getText(); // Iterate over the newly added text and schedule new SpellCheckSpans - final int start = mText.getSpanStart(mRange); - final int end = mText.getSpanEnd(mRange); - mWordIterator.setCharSequence(mText, start, end); + final int start = editable.getSpanStart(mRange); + final int end = editable.getSpanEnd(mRange); + mWordIterator.setCharSequence(editable, start, end); // Move back to the beginning of the current word, if any int wordStart = mWordIterator.preceding(start); @@ -333,14 +336,16 @@ public class SpellChecker implements SpellCheckerSessionListener { wordEnd = mWordIterator.getEnd(wordStart); } if (wordEnd == BreakIterator.DONE) { - mText.removeSpan(mRange); + editable.removeSpan(mRange); return; } // We need to expand by one character because we want to include the spans that // end/start at position start/end respectively. - SpellCheckSpan[] spellCheckSpans = mText.getSpans(start-1, end+1, SpellCheckSpan.class); - SuggestionSpan[] suggestionSpans = mText.getSpans(start-1, end+1, SuggestionSpan.class); + SpellCheckSpan[] spellCheckSpans = editable.getSpans(start - 1, end + 1, + SpellCheckSpan.class); + SuggestionSpan[] suggestionSpans = editable.getSpans(start - 1, end + 1, + SuggestionSpan.class); int nbWordsChecked = 0; boolean scheduleOtherSpellCheck = false; @@ -350,20 +355,20 @@ public class SpellChecker implements SpellCheckerSessionListener { // A new word has been created across the interval boundaries with this edit. // Previous spans (ended on start / started on end) removed, not valid anymore if (wordStart < start && wordEnd > start) { - removeSpansAt(start, spellCheckSpans); - removeSpansAt(start, suggestionSpans); + removeSpansAt(editable, start, spellCheckSpans); + removeSpansAt(editable, start, suggestionSpans); } if (wordStart < end && wordEnd > end) { - removeSpansAt(end, spellCheckSpans); - removeSpansAt(end, suggestionSpans); + removeSpansAt(editable, end, spellCheckSpans); + removeSpansAt(editable, end, suggestionSpans); } // Do not create new boundary spans if they already exist boolean createSpellCheckSpan = true; if (wordEnd == start) { for (int i = 0; i < spellCheckSpans.length; i++) { - final int spanEnd = mText.getSpanEnd(spellCheckSpans[i]); + final int spanEnd = editable.getSpanEnd(spellCheckSpans[i]); if (spanEnd == start) { createSpellCheckSpan = false; break; @@ -373,7 +378,7 @@ public class SpellChecker implements SpellCheckerSessionListener { if (wordStart == end) { for (int i = 0; i < spellCheckSpans.length; i++) { - final int spanStart = mText.getSpanStart(spellCheckSpans[i]); + final int spanStart = editable.getSpanStart(spellCheckSpans[i]); if (spanStart == end) { createSpellCheckSpan = false; break; @@ -386,7 +391,7 @@ public class SpellChecker implements SpellCheckerSessionListener { scheduleOtherSpellCheck = true; break; } - addSpellCheckSpan(wordStart, wordEnd); + addSpellCheckSpan(editable, wordStart, wordEnd); nbWordsChecked++; } } @@ -401,23 +406,23 @@ public class SpellChecker implements SpellCheckerSessionListener { } if (scheduleOtherSpellCheck) { - mText.setSpan(mRange, wordStart, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + editable.setSpan(mRange, wordStart, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { - mText.removeSpan(mRange); + editable.removeSpan(mRange); } spellCheck(); } - private <T> void removeSpansAt(int offset, T[] spans) { + private <T> void removeSpansAt(Editable editable, int offset, T[] spans) { final int length = spans.length; for (int i = 0; i < length; i++) { final T span = spans[i]; - final int start = mText.getSpanStart(span); + final int start = editable.getSpanStart(span); if (start > offset) continue; - final int end = mText.getSpanEnd(span); + final int end = editable.getSpanEnd(span); if (end < offset) continue; - mText.removeSpan(span); + editable.removeSpan(span); } } } diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java index daabf425a461..77d0c97bbf62 100644 --- a/core/java/com/android/internal/app/ShutdownThread.java +++ b/core/java/com/android/internal/app/ShutdownThread.java @@ -109,7 +109,6 @@ public final class ShutdownThread extends Thread { if (confirm) { final CloseDialogReceiver closer = new CloseDialogReceiver(context); final AlertDialog dialog = new AlertDialog.Builder(context) - .setIconAttribute(android.R.attr.alertDialogIcon) .setTitle(com.android.internal.R.string.power_off) .setMessage(resourceId) .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() { diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 97bbe5218b70..5b49bffd8f02 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -17,8 +17,6 @@ package com.android.internal.widget; -import com.android.internal.R; - import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; @@ -39,6 +37,10 @@ import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; + +import com.android.internal.R; import java.util.ArrayList; import java.util.List; @@ -401,6 +403,34 @@ public class LockPatternView extends View { invalidate(); } + private void notifyCellAdded() { + if (mOnPatternListener != null) { + mOnPatternListener.onPatternCellAdded(mPattern); + } + sendAccessEvent(R.string.lockscreen_access_pattern_cell_added); + } + + private void notifyPatternStarted() { + if (mOnPatternListener != null) { + mOnPatternListener.onPatternStart(); + } + sendAccessEvent(R.string.lockscreen_access_pattern_start); + } + + private void notifyPatternDetected() { + if (mOnPatternListener != null) { + mOnPatternListener.onPatternDetected(mPattern); + } + sendAccessEvent(R.string.lockscreen_access_pattern_detected); + } + + private void notifyPatternCleared() { + if (mOnPatternListener != null) { + mOnPatternListener.onPatternCleared(); + } + sendAccessEvent(R.string.lockscreen_access_pattern_cleared); + } + /** * Clear the pattern. */ @@ -554,9 +584,7 @@ public class LockPatternView extends View { private void addCellToPattern(Cell newCell) { mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true; mPattern.add(newCell); - if (mOnPatternListener != null) { - mOnPatternListener.onPatternCellAdded(mPattern); - } + notifyCellAdded(); } // helper method to find which cell a point maps to @@ -619,6 +647,27 @@ public class LockPatternView extends View { } @Override + public boolean onHoverEvent(MotionEvent event) { + if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) { + final int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_HOVER_ENTER: + event.setAction(MotionEvent.ACTION_DOWN); + break; + case MotionEvent.ACTION_HOVER_MOVE: + event.setAction(MotionEvent.ACTION_MOVE); + break; + case MotionEvent.ACTION_HOVER_EXIT: + event.setAction(MotionEvent.ACTION_UP); + break; + } + onTouchEvent(event); + event.setAction(action); + } + return super.onHoverEvent(event); + } + + @Override public boolean onTouchEvent(MotionEvent event) { if (!mInputEnabled || !isEnabled()) { return false; @@ -636,10 +685,8 @@ public class LockPatternView extends View { return true; case MotionEvent.ACTION_CANCEL: resetPattern(); - if (mOnPatternListener != null) { - mPatternInProgress = false; - mOnPatternListener.onPatternCleared(); - } + mPatternInProgress = false; + notifyPatternCleared(); if (PROFILE_DRAWING) { if (mDrawingProfilingStarted) { Debug.stopMethodTracing(); @@ -661,9 +708,9 @@ public class LockPatternView extends View { final int patternSizePreHitDetect = mPattern.size(); Cell hitCell = detectAndAddHit(x, y); final int patternSize = mPattern.size(); - if (hitCell != null && (mOnPatternListener != null) && (patternSize == 1)) { + if (hitCell != null && patternSize == 1) { mPatternInProgress = true; - mOnPatternListener.onPatternStart(); + notifyPatternStarted(); } // note current x and y for rubber banding of in progress patterns final float dx = Math.abs(x - mInProgressX); @@ -778,11 +825,17 @@ public class LockPatternView extends View { } } + private void sendAccessEvent(int resId) { + setContentDescription(mContext.getString(resId)); + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + setContentDescription(null); + } + private void handleActionUp(MotionEvent event) { // report pattern detected - if (!mPattern.isEmpty() && mOnPatternListener != null) { + if (!mPattern.isEmpty()) { mPatternInProgress = false; - mOnPatternListener.onPatternDetected(mPattern); + notifyPatternDetected(); invalidate(); } if (PROFILE_DRAWING) { @@ -798,13 +851,13 @@ public class LockPatternView extends View { final float x = event.getX(); final float y = event.getY(); final Cell hitCell = detectAndAddHit(x, y); - if (hitCell != null && mOnPatternListener != null) { + if (hitCell != null) { mPatternInProgress = true; mPatternDisplayMode = DisplayMode.Correct; - mOnPatternListener.onPatternStart(); - } else if (mOnPatternListener != null) { + notifyPatternStarted(); + } else { mPatternInProgress = false; - mOnPatternListener.onPatternCleared(); + notifyPatternCleared(); } if (hitCell != null) { final float startX = getCenterXForColumn(hitCell.column); diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java index 1042a59d6d24..73d9f10104f4 100644 --- a/core/java/com/android/internal/widget/TransportControlView.java +++ b/core/java/com/android/internal/widget/TransportControlView.java @@ -336,20 +336,27 @@ public class TransportControlView extends FrameLayout implements OnClickListener if (state == mPlayState) { return; } + final int imageResId; + final int imageDescId; switch (state) { case RemoteControlClient.PLAYSTATE_PLAYING: - mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_pause); + imageResId = com.android.internal.R.drawable.ic_media_pause; + imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description; break; case RemoteControlClient.PLAYSTATE_BUFFERING: - mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_stop); + imageResId = com.android.internal.R.drawable.ic_media_stop; + imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description; break; case RemoteControlClient.PLAYSTATE_PAUSED: default: - mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_play); + imageResId = com.android.internal.R.drawable.ic_media_play; + imageDescId = com.android.internal.R.string.lockscreen_transport_play_description; break; } + mBtnPlay.setImageResource(imageResId); + mBtnPlay.setContentDescription(getResources().getString(imageDescId)); mPlayState = state; } diff --git a/core/res/res/drawable-hdpi/stat_notify_disabled.png b/core/res/res/drawable-hdpi/stat_notify_disabled.png Binary files differnew file mode 100644 index 000000000000..5b5a7dcc6969 --- /dev/null +++ b/core/res/res/drawable-hdpi/stat_notify_disabled.png diff --git a/core/res/res/drawable-mdpi/stat_notify_disabled.png b/core/res/res/drawable-mdpi/stat_notify_disabled.png Binary files differnew file mode 100644 index 000000000000..9661d3149dc3 --- /dev/null +++ b/core/res/res/drawable-mdpi/stat_notify_disabled.png diff --git a/core/res/res/drawable-xhdpi/stat_notify_disabled.png b/core/res/res/drawable-xhdpi/stat_notify_disabled.png Binary files differnew file mode 100644 index 000000000000..0a003af6fc9d --- /dev/null +++ b/core/res/res/drawable-xhdpi/stat_notify_disabled.png diff --git a/core/res/res/layout/keyguard_transport_control.xml b/core/res/res/layout/keyguard_transport_control.xml index 2ebe5fceddc2..6e24ce249f5b 100644 --- a/core/res/res/layout/keyguard_transport_control.xml +++ b/core/res/res/layout/keyguard_transport_control.xml @@ -66,7 +66,8 @@ android:src="@drawable/ic_media_rew" android:clickable="true" android:background="?android:attr/selectableItemBackground" - android:padding="10dip"/> + android:padding="10dip" + android:contentDescription="@string/lockscreen_transport_prev_description"/> </FrameLayout> <FrameLayout android:layout_width="wrap_content" @@ -80,7 +81,8 @@ android:clickable="true" android:src="@drawable/ic_media_play" android:background="?android:attr/selectableItemBackground" - android:padding="10dip"/> + android:padding="10dip" + android:contentDescription="@string/lockscreen_transport_play_description"/> </FrameLayout> <FrameLayout android:layout_width="wrap_content" @@ -94,7 +96,8 @@ android:clickable="true" android:src="@drawable/ic_media_ff" android:background="?android:attr/selectableItemBackground" - android:padding="10dip"/> + android:padding="10dip" + android:contentDescription="@string/lockscreen_transport_next_description"/> </FrameLayout> </LinearLayout> </LinearLayout> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index b1dc252d16dc..fb4783b51802 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -953,7 +953,7 @@ social updates from your friends. Malicious apps can use this to pretend to be a friend and trick you into revealing passwords or other confidential information.</string> - + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_readCalendar">read calendar events plus confidential information</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> @@ -1831,6 +1831,17 @@ <string name="lockscreen_permanent_disabled_sim_instructions">Your SIM card is permanently disabled.\n Please contact your wireless service provider to obtain another SIM card.</string> + <!-- Shown on transport control of lockscreen. Pressing button goes to previous track. --> + <string name="lockscreen_transport_prev_description">Previous track button</string> + <!-- Shown on transport control of lockscreen. Pressing button goes to next track. --> + <string name="lockscreen_transport_next_description">Next track button</string> + <!-- Shown on transport control of lockscreen. Pressing button pauses playback --> + <string name="lockscreen_transport_pause_description">Pause button</string> + <!-- Shown on transport control of lockscreen. Pressing button pauses playback --> + <string name="lockscreen_transport_play_description">Play button</string> + <!-- Shown on transport control of lockscreen. Pressing button pauses playback --> + <string name="lockscreen_transport_stop_description">Stop button</string> + <!-- Shown in the lock screen when there is emergency calls only mode. --> <string name="emergency_calls_only" msgid="2485604591272668370">Emergency calls only</string> @@ -1958,6 +1969,15 @@ <!-- Displayed on lock screen's right tab - turn sound off --> <string name="lockscreen_sound_off_label">Sound off</string> + <!-- Accessibility description sent when user starts drawing a lock pattern. [CHAR LIMIT=NONE] --> + <string name="lockscreen_access_pattern_start">Pattern started</string> + <!-- Accessibility description sent when the pattern times out and is cleared. [CHAR LIMIT=NONE] --> + <string name="lockscreen_access_pattern_cleared">Pattern cleared</string> + <!-- Accessibility description sent when user adds a cell to the pattern. [CHAR LIMIT=NONE] --> + <string name="lockscreen_access_pattern_cell_added">Cell added</string> + <!-- Accessibility description sent when user completes drawing a pattern. [CHAR LIMIT=NONE] --> + <string name="lockscreen_access_pattern_detected">Pattern completed</string> + <!-- Password keyboard strings. Used by LockScreen and Settings --><skip /> <!-- Label for "switch to symbols" key. Must be short to fit on key! --> <string name="password_keyboard_label_symbol_key">\?123</string> diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk index 564f41cb4cf6..c96496195849 100644 --- a/data/keyboards/keyboards.mk +++ b/data/keyboards/keyboards.mk @@ -24,6 +24,3 @@ PRODUCT_COPY_FILES += $(foreach file,$(keycharmaps),\ PRODUCT_COPY_FILES += $(foreach file,$(keyconfigs),\ frameworks/base/data/keyboards/$(file):system/usr/idc/$(file)) - -PRODUCT_PACKAGES := $(keylayouts) $(keycharmaps) $(keyconfigs) - diff --git a/data/sounds/AudioPackage7.mk b/data/sounds/AudioPackage7.mk index 629ceb356d7c..66edb7a745d5 100755 --- a/data/sounds/AudioPackage7.mk +++ b/data/sounds/AudioPackage7.mk @@ -27,35 +27,33 @@ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \ $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \ - $(LOCAL_PATH)/notifications/ogg/Altair.ogg:system/media/audio/notifications/Altair.ogg \ $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Betelgeuse.ogg:system/media/audio/notifications/Betelgeuse.ogg \ + $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \ $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \ $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Deneb.ogg:system/media/audio/notifications/Deneb.ogg \ $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \ $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \ $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \ $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \ + $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \ $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \ $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \ - $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \ $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \ $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \ + $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \ + $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \ $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Acheron.ogg:system/media/audio/ringtones/Acheron.ogg \ $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \ $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \ $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \ $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Cassiopeia.ogg:system/media/audio/ringtones/Cassiopeia.ogg \ $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \ $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \ $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \ $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \ $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Nasqueron.ogg:system/media/audio/ringtones/Nasqueron.ogg \ $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \ $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \ $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \ @@ -66,4 +64,4 @@ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \ $(LOCAL_PATH)/ringtones/ogg/Testudo.ogg:system/media/audio/ringtones/Testudo.ogg \ $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg + $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg diff --git a/data/sounds/effects/ogg/Lock.ogg b/data/sounds/effects/ogg/Lock.ogg Binary files differindex ed845bee50e3..e7928e493f40 100644 --- a/data/sounds/effects/ogg/Lock.ogg +++ b/data/sounds/effects/ogg/Lock.ogg diff --git a/data/sounds/effects/ogg/Unlock.ogg b/data/sounds/effects/ogg/Unlock.ogg Binary files differindex 0a47b5c23095..cca95940d950 100644 --- a/data/sounds/effects/ogg/Unlock.ogg +++ b/data/sounds/effects/ogg/Unlock.ogg diff --git a/data/sounds/effects/wav/Lock.wav b/data/sounds/effects/wav/Lock.wav Binary files differindex 1655a8902f5f..b8076369a3e9 100644 --- a/data/sounds/effects/wav/Lock.wav +++ b/data/sounds/effects/wav/Lock.wav diff --git a/data/sounds/effects/wav/Unlock.wav b/data/sounds/effects/wav/Unlock.wav Binary files differindex 2229d03b5fed..e1d475ed84dd 100644 --- a/data/sounds/effects/wav/Unlock.wav +++ b/data/sounds/effects/wav/Unlock.wav diff --git a/data/sounds/notifications/ogg/Acrux.ogg b/data/sounds/notifications/ogg/Acrux.ogg Binary files differnew file mode 100644 index 000000000000..74ad149a7191 --- /dev/null +++ b/data/sounds/notifications/ogg/Acrux.ogg diff --git a/data/sounds/notifications/ogg/Bellatrix.ogg b/data/sounds/notifications/ogg/Bellatrix.ogg Binary files differnew file mode 100644 index 000000000000..37a1bdcaabdf --- /dev/null +++ b/data/sounds/notifications/ogg/Bellatrix.ogg diff --git a/data/sounds/notifications/ogg/Pollux.ogg b/data/sounds/notifications/ogg/Pollux.ogg Binary files differnew file mode 100644 index 000000000000..2f907fdb1909 --- /dev/null +++ b/data/sounds/notifications/ogg/Pollux.ogg diff --git a/data/sounds/notifications/ogg/Tejat.ogg b/data/sounds/notifications/ogg/Tejat.ogg Binary files differnew file mode 100644 index 000000000000..04ba06cef9b0 --- /dev/null +++ b/data/sounds/notifications/ogg/Tejat.ogg diff --git a/data/sounds/ringtones/ogg/Girtab.ogg b/data/sounds/ringtones/ogg/Girtab.ogg Binary files differnew file mode 100644 index 000000000000..f6b3a35a3859 --- /dev/null +++ b/data/sounds/ringtones/ogg/Girtab.ogg diff --git a/data/sounds/ringtones/ogg/Zeta.ogg b/data/sounds/ringtones/ogg/Zeta.ogg Binary files differnew file mode 100644 index 000000000000..ef64d2feda7e --- /dev/null +++ b/data/sounds/ringtones/ogg/Zeta.ogg diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd index b2a78fe98222..5a9313e7f70c 100644 --- a/docs/html/guide/topics/manifest/activity-element.jd +++ b/docs/html/guide/topics/manifest/activity-element.jd @@ -581,8 +581,9 @@ resource usage. </p></dd> <dt><a name="screen"></a>{@code android:screenOrientation}</dt> -<dd>The orientation of the activity's display on the device. -The value can be any one of the following strings: +<dd>The orientation of the activity's display on the device. + +<p>The value can be any one of the following strings:</p> <table> <tr> @@ -640,7 +641,23 @@ is ignored, so the display will not rotate based on how the user moves the devic distinction, the system chooses the orientation using the same policy as for the "{@code unspecified}" setting.</td> </tr> -</table></dd> +</table> + +<p class="note"><strong>Note:</strong> When you declare one of the landscape or portrait values, +it is considered a hard requirement for the orientation in which the activity runs. As such, +the value you declare enables filtering by services such as Android Market so your application is +available only to devices that support the orientation required by your activities. For +example, if you declare either {@code "landscape"}, {@code "reverseLandscape"}, or +{@code "sensorLandscape"}, then your application will be available only to devices that support +landscape orientation. However, you should also explicitly declare that +your application requires either portrait or landscape orientation with the <a +href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a> +element. For example, <code><uses-feature +android:name="android.hardware.screen.portrait"/></code>. This is purely a filtering behavior +provided by Android Market (and other services that support it) and the platform itself does not +control whether your app can be installed when a device supports only certain orientations.</p> + +</dd> <dt><a name="state"></a>{@code android:stateNotNeeded}</dt> <dd>Whether or not the activity can be killed and successfully restarted diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd index 49d6b6204779..9f806380e921 100644 --- a/docs/html/guide/topics/manifest/uses-feature-element.jd +++ b/docs/html/guide/topics/manifest/uses-feature-element.jd @@ -111,7 +111,7 @@ the device before installing an application. However, other services with your application. For this reason, it's very important that you declare all of the features (from the list below) that your application uses. </p> -<p>For some features, there may exist a specfic attribute that allows you to define +<p>For some features, there may exist a specific attribute that allows you to define a version of the feature, such as the version of Open GL used (declared with <a href="#glEsVersion"><code>glEsVersion</code></a>). Other features that either do or do not exist for a device, such as a camera, are declared using the @@ -277,7 +277,7 @@ application absolutely requires the feature and cannot function properly without it (<code>"true"</code>), or whether the application prefers to use the feature if available, but is designed to run without it (<code>"false"</code>).</p> -<p>Android Market handles explictly declared features in this way: </p> +<p>Android Market handles explicitly declared features in this way: </p> <ul> <li>If a feature is explicitly declared as being required, Android Market adds @@ -287,7 +287,7 @@ For example: <pre><uses-feature android:name="android.hardware.camera" android:required="true" /></pre></li> <li>If a feature is explicitly declared as <em>not</em> being required, Android Market <em>does not</em> add the feature to the list of required features. For -that reason, an explicity declared non-required feature is never considered when +that reason, an explicitly declared non-required feature is never considered when filtering the application. Even if the device does not provide the declared feature, Android Market will still consider the application compatible with the device and will show it to the user, unless other filtering rules apply. For @@ -650,6 +650,40 @@ the device.</td> <td>The application uses the device's proximity sensor.</td> <td></td> </tr> + +<tr> + <td rowspan="2">Screen</td> + <td><code>android.hardware.screen.landscape</code></td> + <td>The application requires landscape orientation.</td> + <td rowspan="2"> + <p>For example, if your app requires portrait orientation, you should declare +<code><uses-feature android:name="android.hardware.screen.portrait"/></code> so that only devices +that support portrait orientation (whether always or by user choice) can install your app. If your +application <em>supports</em> both orientations, then you don't need to declare either.</p> + <p>Both orientations are assumed <em>not required</em>, by default, so your app may be installed +on devices that support one or both orientations. However, if any of your activities request that +they run in a specific orientation, using the <a +href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code +android:screenOrientation}</a> attribute, then this also declares that the application requires that +orientation. For example, if you declare <a +href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code +android:screenOrientation}</a> with either {@code "landscape"}, {@code "reverseLandscape"}, or +{@code "sensorLandscape"}, then your application will be available only to devices that support +landscape orientation. As a best practice, you should still declare your requirement for this +orientation using a {@code <uses-feature>} element. If you declare an orientation for your +activity using <a href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code +android:screenOrientation}</a>, but don't actually <em>require</em> it, you can disable the +requirement by declaring the orientation with a {@code <uses-feature>} element and include +{@code android:required="false"}.</p> + <p>For backwards compatibility, any device running a platform version that supports only API +level 12 or lower is assumed to support both landscape and portrait.</p> + </td> +</tr> +<tr> + <td><code>android.hardware.screen.portrait</code></td> + <td>The application requires portrait orientation.</td> +</tr> + <tr> <td rowspan="3">Telephony</td> <td><code>android.hardware.telephony</code></td> @@ -672,17 +706,18 @@ device.</td> </tr> <tr> - <td rowspan="5">Touchscreen</td> + <td rowspan="7">Touchscreen</td> <td><code>android.hardware.faketouch</code></td> <td>The application uses basic touch interaction events, such as "click down", "click up", and drag.</td> - <td>When declared, this indicates that the application is compatible with a device that offers an -emulated touchscreen ("fake touch" interface), or better. A device that offers a fake touch -interface provides a user input system that emulates a subset of touchscreen capabilities. For -example, a mouse or remote control that drives an on-screen cursor provides a fake touch interface. -If your application requires only basic point and click interaction, you should declare this -feature. Because this is the minimum level of touch interaction, your app will also be compatible -with devices that offer more complex touch interfaces. + <td><p>When declared as required, this indicates that the application is compatible with a device +only if it offers an emulated touchscreen ("fake touch" interface), or better. A device that offers +a fake touch interface provides a user input system that emulates a subset of touchscreen +capabilities. For example, a mouse or remote control that drives an on-screen cursor provides a fake +touch interface. If your application requires basic point and click interaction (in other +words, it won't work with <em>only</em> a d-pad controller), you should declare this feature. +Because this is the minimum level of touch interaction, your app will also be compatible with +devices that offer more complex touch interfaces.</p> <p class="note"><strong>Note:</strong> Because applications require the {@code android.hardware.touchscreen} feature by default, if you want your application to be available to devices that provide a fake touch interface, you must also explicitly declare that a touch screen is @@ -690,18 +725,53 @@ devices that provide a fake touch interface, you must also explicitly declare th android:name="android.hardware.touchscreen" <strong>android:required="false"</strong> />}</p></td> </tr> + +<tr> + <td><code>android.hardware.faketouch.multitouch.distinct</code></td> + <td>The application performs distinct tracking of two or more "fingers" on a fake touch +interface. This is a superset of the faketouch feature.</td> + <td><p>When declared as required, this indicates that the application is compatible with a device +only if it supports touch emulation for events that supports distinct tracking of two or more +fingers, or better.</p> + <p>Unlike the distinct multitouch defined by {@code +android.hardware.touchscreen.multitouch.distinct}, input devices that support distinct multi-touch +with a fake touch interface will not support all two-finger gestures, because the input is +being transformed to cursor movement on the screen. That is, single finger gestures on such a device +move a cursor; two-finger swipes will result in single-finger touch events; other two-finger +gestures will result in the corresponding two-finger touch event. An example device that supports +distinct multi-touch with a fake touch interface is one that provides a trackpad for cursor movement +which also supports two or more fingers.</p></td> +</tr> + +<tr> + <td><code>android.hardware.faketouch.multitouch.jazzhand</code></td> + <td>The application performs distinct tracking of five or more "fingers" on a fake touch +interface. This is a superset of the faketouch feature.</td> + <td><p>When declared as required, this indicates that the application is compatible with a device +only if it supports touch emulation for events that supports distinct tracking of five or more +fingers.</p> + <p>Unlike the distinct multitouch defined by {@code +android.hardware.touchscreen.multitouch.jazzhand}, input devices that support jazzhand multi-touch +with a fake touch interface will not support all five-finger gestures, because the input is being +transformed to cursor movement on the screen. That is, single finger gestures on such a device move +a cursor; multi-finger gestures will result in single-finger touch events; other multi-finger +gestures will result in the corresponding multi-finger touch event. An example device that supports +distinct multi-touch with a fake touch interface is one that provides a trackpad for cursor movement +which also supports five or more fingers.</p></td> +</tr> + <tr> <td><code>android.hardware.touchscreen</code></td> <td>The application uses touchscreen capabilities for gestures that are more interactive -than basic touch events, such as a fling. This is a superset of the faketouch features.</td> - <td>By default, your application requires this. As such, your application is -<em>not</em> available to devices that provide only an emulated touch interface ("fake touch"), by -default. If you want your application available to devices that provide a fake touch interface, -you must explicitly declare that a touch screen is not required, by -declaring {@code android.hardware.touchscreen} with {@code android:required="false"}. You should -do so even if your application uses—but does not <em>require</em>—a real touch screen -interface. -<p>If your application <em>does require</em> a basic touch interface (in order to perform touch +than basic touch events, such as a fling. This is a superset of the basic faketouch feature.</td> + <td><p>By default, your application requires this. As such, your application is <em>not</em> +available to devices that provide only an emulated touch interface ("fake touch"), by default. If +you want your application available to devices that provide a fake touch interface (or even devices +that provide only a d-pad controller), you must explicitly declare that a touch screen is not +required, by declaring {@code android.hardware.touchscreen} with {@code android:required="false"}. +You should do so even if your application uses—but does not <em>require</em>—a real +touch screen interface.</p> +<p>If your application <em>does require</em> a touch interface (in order to perform touch gestures such as a fling), then you don't need to do anything, because this is required by default. However, it's best if you explicitly declare all features used by your application, so you should still declare this if your app uses it.</p> @@ -712,7 +782,7 @@ should declare the advanced touch screen features below.</p></td> <td><code>android.hardware.touchscreen.multitouch</code></td> <td>The application uses basic two-point multitouch capabilities on the device screen, such as for pinch gestures, but does not need to track touches independently. This -is a superset of touchscreen features.</td> +is a superset of touchscreen feature.</td> <td>This implicitly declares the <code>android.hardware.touchscreen</code> parent feature, unless declared with <code>android:required="false"</code>. </td> </tr> @@ -720,7 +790,7 @@ declared with <code>android:required="false"</code>. </td> <td><code>android.hardware.touchscreen.multitouch.distinct</code></td> <td>Subfeature. The application uses advanced multipoint multitouch capabilities on the device screen, such as for tracking two or more points fully -independently. This is a superset of multitouch features.</td> +independently. This is a superset of multitouch feature.</td> <td rowspan="2">This implicitly declares the <code>android.hardware.touchscreen.multitouch</code> parent feature, unless declared with <code>android:required="false"</code>. </td> </tr> @@ -728,7 +798,7 @@ parent feature, unless declared with <code>android:required="false"</code>. </td <td><code>android.hardware.touchscreen.multitouch.jazzhand</code></td> <td>The application uses advanced multipoint multitouch capabilities on the device screen, for tracking up to five points fully -independently. This is a superset of distinct multitouch features.</td> +independently. This is a superset of distinct multitouch feature.</td> </tr> <tr> diff --git a/docs/html/sdk/android-3.2.jd b/docs/html/sdk/android-3.2.jd index ea2b4ed6ad2e..aeaf9c8171ed 100644 --- a/docs/html/sdk/android-3.2.jd +++ b/docs/html/sdk/android-3.2.jd @@ -550,7 +550,11 @@ portrait orientation.</li> <p>A typical application that functions properly in both landscape and portrait orientations would not normally need to declare an orientation requirement. Rather, an application designed primarily for one orientation, such as an app designed for a television, could declare one of the constants to ensure that it isn't available to devices that don't provide that orientation.</p> -<p>If the application is targeting API level 12 or lower, the platform assumes that if app has not specified whether it requires portrait or landscape, both orientations are required.</p> +<p>If any of activities declared in the manifest request that they run in a specific orientation, +using the <a href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code +android:screenOrientation}</a> attribute, then this also declares that the application +requires that orientation.</p> + </li> <li>Other feature constants diff --git a/media/java/android/media/videoeditor/AudioTrack.java b/media/java/android/media/videoeditor/AudioTrack.java index 2de82f25ecb6..c5cc2cad05de 100755 --- a/media/java/android/media/videoeditor/AudioTrack.java +++ b/media/java/android/media/videoeditor/AudioTrack.java @@ -147,14 +147,16 @@ public class AudioTrack { } catch (Exception e) { throw new IllegalArgumentException(e.getMessage() + " : " + filename); } - switch (mMANativeHelper.getFileType(properties.fileType)) { + int fileType = mMANativeHelper.getFileType(properties.fileType); + switch (fileType) { case MediaProperties.FILE_3GP: case MediaProperties.FILE_MP4: case MediaProperties.FILE_MP3: + case MediaProperties.FILE_AMR: break; default: { - throw new IllegalArgumentException("Unsupported input file type"); + throw new IllegalArgumentException("Unsupported input file type: " + fileType); } } switch (mMANativeHelper.getAudioCodecType(properties.audioFormat)) { diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java index d7b8eaa844ec..03ae62ac1e53 100644 --- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java +++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java @@ -3239,6 +3239,9 @@ class MediaArtistNativeHelper { case FileType.M4V: retValue = MediaProperties.FILE_M4V; break; + case FileType.AMR: + retValue = MediaProperties.FILE_AMR; + break; default: retValue = -1; diff --git a/media/java/android/media/videoeditor/MediaProperties.java b/media/java/android/media/videoeditor/MediaProperties.java index fd034abb03ae..cf518a5f3d7a 100755 --- a/media/java/android/media/videoeditor/MediaProperties.java +++ b/media/java/android/media/videoeditor/MediaProperties.java @@ -286,7 +286,7 @@ public class MediaProperties { */ public static final int FILE_3GP = 0; public static final int FILE_MP4 = 1; - // 2 is for AMRNB + public static final int FILE_AMR = 2; public static final int FILE_MP3 = 3; // 4 is for PCM public static final int FILE_JPEG = 5; diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index fa9417a50ebe..1165af5183a6 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -2005,6 +2005,11 @@ status_t AwesomePlayer::finishSetDataSource_l() { mConnectingDataSource->setUID(mUID); } + String8 cacheConfig; + bool disconnectAtHighwatermark; + NuCachedSource2::RemoveCacheSpecificHeaders( + &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark); + mLock.unlock(); status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); mLock.lock(); @@ -2024,7 +2029,10 @@ status_t AwesomePlayer::finishSetDataSource_l() { new ThrottledSource( mConnectingDataSource, 50 * 1024 /* bytes/sec */)); #else - mCachedSource = new NuCachedSource2(mConnectingDataSource); + mCachedSource = new NuCachedSource2( + mConnectingDataSource, + cacheConfig.isEmpty() ? NULL : cacheConfig.string(), + disconnectAtHighwatermark); #endif dataSource = mCachedSource; diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index 9adb841d5989..4f183f57bb64 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -177,7 +177,10 @@ void PageCache::copy(size_t from, void *data, size_t size) { //////////////////////////////////////////////////////////////////////////////// -NuCachedSource2::NuCachedSource2(const sp<DataSource> &source) +NuCachedSource2::NuCachedSource2( + const sp<DataSource> &source, + const char *cacheConfig, + bool disconnectAtHighwatermark) : mSource(source), mReflector(new AHandlerReflector<NuCachedSource2>(this)), mLooper(new ALooper), @@ -190,9 +193,24 @@ NuCachedSource2::NuCachedSource2(const sp<DataSource> &source) mNumRetriesLeft(kMaxNumRetries), mHighwaterThresholdBytes(kDefaultHighWaterThreshold), mLowwaterThresholdBytes(kDefaultLowWaterThreshold), - mKeepAliveIntervalUs(kDefaultKeepAliveIntervalUs) { + mKeepAliveIntervalUs(kDefaultKeepAliveIntervalUs), + mDisconnectAtHighwatermark(disconnectAtHighwatermark) { + // We are NOT going to support disconnect-at-highwatermark indefinitely + // and we are not guaranteeing support for client-specified cache + // parameters. Both of these are temporary measures to solve a specific + // problem that will be solved in a better way going forward. + updateCacheParamsFromSystemProperty(); + if (cacheConfig != NULL) { + updateCacheParamsFromString(cacheConfig); + } + + if (mDisconnectAtHighwatermark) { + // Makes no sense to disconnect and do keep-alives... + mKeepAliveIntervalUs = 0; + } + mLooper->setName("NuCachedSource2"); mLooper->registerHandler(mReflector); mLooper->start(); @@ -339,6 +357,12 @@ void NuCachedSource2::onFetch() { if (mFetching && mCache->totalSize() >= mHighwaterThresholdBytes) { LOGI("Cache full, done prefetching for now"); mFetching = false; + + if (mDisconnectAtHighwatermark + && (mSource->flags() & DataSource::kIsHTTPBasedSource)) { + LOGV("Disconnecting at high watermark"); + static_cast<HTTPBase *>(mSource.get())->disconnect(); + } } } else { Mutex::Autolock autoLock(mLock); @@ -637,4 +661,34 @@ void NuCachedSource2::updateCacheParamsFromString(const char *s) { mKeepAliveIntervalUs); } +// static +void NuCachedSource2::RemoveCacheSpecificHeaders( + KeyedVector<String8, String8> *headers, + String8 *cacheConfig, + bool *disconnectAtHighwatermark) { + *cacheConfig = String8(); + *disconnectAtHighwatermark = false; + + if (headers == NULL) { + return; + } + + ssize_t index; + if ((index = headers->indexOfKey(String8("x-cache-config"))) >= 0) { + *cacheConfig = headers->valueAt(index); + + headers->removeItemsAt(index); + + LOGV("Using special cache config '%s'", cacheConfig->string()); + } + + if ((index = headers->indexOfKey( + String8("x-disconnect-at-highwatermark"))) >= 0) { + *disconnectAtHighwatermark = true; + headers->removeItemsAt(index); + + LOGV("Client requested disconnection at highwater mark"); + } +} + } // namespace android diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h index f04c56664713..7a03e7e4f976 100644 --- a/media/libstagefright/include/NuCachedSource2.h +++ b/media/libstagefright/include/NuCachedSource2.h @@ -28,7 +28,10 @@ struct ALooper; struct PageCache; struct NuCachedSource2 : public DataSource { - NuCachedSource2(const sp<DataSource> &source); + NuCachedSource2( + const sp<DataSource> &source, + const char *cacheConfig = NULL, + bool disconnectAtHighwatermark = false); virtual status_t initCheck() const; @@ -56,6 +59,11 @@ struct NuCachedSource2 : public DataSource { status_t getEstimatedBandwidthKbps(int32_t *kbps); status_t setCacheStatCollectFreq(int32_t freqMs); + static void RemoveCacheSpecificHeaders( + KeyedVector<String8, String8> *headers, + String8 *cacheConfig, + bool *disconnectAtHighwatermark); + protected: virtual ~NuCachedSource2(); @@ -105,6 +113,8 @@ private: // If the keep-alive interval is 0, keep-alives are disabled. int64_t mKeepAliveIntervalUs; + bool mDisconnectAtHighwatermark; + void onMessageReceived(const sp<AMessage> &msg); void onFetch(); void onRead(const sp<AMessage> &msg); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index b851ab7ec81c..244482915490 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -350,16 +350,21 @@ public class SettingsBackupAgent extends BackupAgentHelper { private byte[] getSystemSettings() { Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null, null, null); - byte[] result = extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP); - cursor.close(); - return result; + try { + return extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP); + } finally { + cursor.close(); + } } private byte[] getSecureSettings() { Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null, null, null); - byte[] result = extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP); - return result; + try { + return extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP); + } finally { + cursor.close(); + } } private void restoreSettings(BackupDataInput data, Uri contentUri) { diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index 856914359517..11b6c15185d3 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -18,7 +18,6 @@ package com.android.internal.policy.impl; import android.app.Activity; import android.app.AlertDialog; -import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -57,8 +56,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private static final String TAG = "GlobalActions"; - private StatusBarManager mStatusBar; - private final Context mContext; private final AudioManager mAudioManager; @@ -103,13 +100,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mKeyguardShowing = keyguardShowing; mDeviceProvisioned = isDeviceProvisioned; if (mDialog == null) { - mStatusBar = (StatusBarManager)mContext.getSystemService(Context.STATUS_BAR_SERVICE); mDialog = createDialog(); } prepareDialog(); - mStatusBar.disable(StatusBarManager.DISABLE_EXPAND); mDialog.show(); + mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND); } /** @@ -249,7 +245,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac /** {@inheritDoc} */ public void onDismiss(DialogInterface dialog) { - mStatusBar.disable(StatusBarManager.DISABLE_NONE); } /** {@inheritDoc} */ diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java index 24dce1a0dd79..8343bbdf738e 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java @@ -186,6 +186,9 @@ class KeyguardStatusViewManager implements OnClickListener { mTransientTextManager = new TransientTextManager(mCarrierView); + mUpdateMonitor.registerInfoCallback(mInfoCallback); + mUpdateMonitor.registerSimStateCallback(mSimStateCallback); + resetStatusInfo(); refreshDate(); updateOwnerInfo(); diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 10cf3aaf5c0f..f67f0e056d65 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -218,7 +218,7 @@ public class KeyguardUpdateMonitor { // take a guess to start mSimState = IccCard.State.READY; - mBatteryStatus = BATTERY_STATUS_FULL; + mBatteryStatus = BATTERY_STATUS_UNKNOWN; mBatteryLevel = 100; mTelephonyPlmn = getDefaultPlmn(); diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java index 071044ed2b9c..265024be98b5 100644 --- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -98,7 +98,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler private View mLockScreen; private View mUnlockScreen; - private boolean mScreenOn = false; + private volatile boolean mScreenOn = false; + private volatile boolean mWindowFocused = false; private boolean mEnableFallback = false; // assume no fallback UI until we know better private boolean mShowLockBeforeUnlock = false; @@ -110,6 +111,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler private boolean mFaceLockServiceRunning = false; private final Object mFaceLockServiceRunningLock = new Object(); + private final Object mFaceLockStartupLock = new Object(); private Handler mHandler; private final int MSG_SHOW_FACELOCK_AREA_VIEW = 0; @@ -514,13 +516,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler stopAndUnbindFromFaceLock(); } - @Override - public void onScreenTurnedOn() { - mScreenOn = true; - show(); - - // When screen is turned on, need to bind to FaceLock service if we are using FaceLock - // But only if not dealing with a call + /** When screen is turned on and focused, need to bind to FaceLock service if we are using + * FaceLock, but only if we're not dealing with a call + */ + private void activateFaceLockIfAble() { final boolean transportInvisible = mTransportControlView == null ? true : mTransportControlView.getVisibility() != View.VISIBLE; if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE @@ -534,12 +533,34 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler } } - /** Unbind from facelock if something covers this window (such as an alarm) */ + @Override + public void onScreenTurnedOn() { + boolean runFaceLock = false; + //Make sure to start facelock iff the screen is both on and focused + synchronized(mFaceLockStartupLock) { + mScreenOn = true; + runFaceLock = mWindowFocused; + } + show(); + if(runFaceLock) activateFaceLockIfAble(); + } + + /** Unbind from facelock if something covers this window (such as an alarm) + * bind to facelock if the lockscreen window just came into focus, and the screen is on + */ @Override public void onWindowFocusChanged (boolean hasWindowFocus) { + boolean runFaceLock = false; + //Make sure to start facelock iff the screen is both on and focused + synchronized(mFaceLockStartupLock) { + if(mScreenOn && !mWindowFocused) runFaceLock = hasWindowFocus; + mWindowFocused = hasWindowFocus; + } if(!hasWindowFocus) { stopAndUnbindFromFaceLock(); mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW); + } else if (runFaceLock) { + activateFaceLockIfAble(); } } diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 5758954794ff..f9f5458122ff 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -1966,6 +1966,9 @@ class BackupManagerService extends IBackupManager.Stub { synchronized (mQueueLock) { mBackupRunning = false; if (mStatus == BackupConstants.TRANSPORT_NOT_INITIALIZED) { + // Make sure we back up everything and perform the one-time init + clearMetadata(); + if (DEBUG) Slog.d(TAG, "Server requires init; rerunning"); backupNow(); } } @@ -1975,6 +1978,12 @@ class BackupManagerService extends IBackupManager.Stub { mWakelock.release(); } + // Remove the PM metadata state. This will generate an init on the next pass. + void clearMetadata() { + final File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL); + if (pmState.exists()) pmState.delete(); + } + // Invoke an agent's doBackup() and start a timeout message spinning on the main // handler in case it doesn't get back to us. int invokeAgentForBackup(String packageName, IBackupAgent agent, diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 78dbbd6eb555..1941c6aa9342 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -1677,6 +1677,18 @@ public class PowerManagerService extends IPowerManager.Stub e.fillInStackTrace(); Slog.i(TAG, "Set screen state: " + on, e); } + if (on) { + if ((mPowerState & SCREEN_ON_BIT) == 0 || mSkippedScreenOn) { + // If we are turning the screen state on, but the screen + // light is currently off, then make sure that we set the + // light at this point to 0. This is the case where we are + // turning on the screen and waiting for the UI to be drawn + // before showing it to the user. We want the light off + // until it is ready to be shown to the user, not it using + // whatever the last value it had. + mScreenBrightness.forceValueLocked(Power.BRIGHTNESS_OFF); + } + } int err = Power.setScreenState(on); if (err == 0) { mLastScreenOnTime = (on ? SystemClock.elapsedRealtime() : 0); @@ -2029,8 +2041,6 @@ public class PowerManagerService extends IPowerManager.Stub RuntimeException e = new RuntimeException("here"); e.fillInStackTrace(); Slog.i(TAG, "Setting screen brightness: " + brightness, e); - mScreenBrightness.setTargetLocked(brightness, steps, - INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); } } @@ -2103,6 +2113,15 @@ public class PowerManagerService extends IPowerManager.Stub + " delta=" + delta); } + void forceValueLocked(int value) { + targetValue = -1; + curValue = value; + setLightBrightness(mask, value); + if (animating) { + finishAnimationLocked(false, value); + } + } + void setTargetLocked(int target, int stepsToTarget, int initialValue, int nominalCurrentValue) { if (!initialized) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 5006de757cd3..3ae62add369f 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -163,6 +163,11 @@ class ServerThread extends Thread { pm = PackageManagerService.main(context, factoryTest != SystemServer.FACTORY_TEST_OFF, onlyCore); + boolean firstBoot = false; + try { + firstBoot = pm.isFirstBoot(); + } catch (RemoteException e) { + } ActivityManagerService.setSystemProcess(); @@ -208,7 +213,8 @@ class ServerThread extends Thread { Slog.i(TAG, "Window Manager"); wm = WindowManagerService.main(context, power, - factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL); + factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL, + !firstBoot); ServiceManager.addService(Context.WINDOW_SERVICE, wm); ActivityManagerService.self().setWindowManager(wm); diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 7bc19ab43882..b9d3d76bbd11 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -589,8 +589,8 @@ final class ActivityStack { } } app.thread.scheduleLaunchActivity(new Intent(r.intent), r, - System.identityHashCode(r), - r.info, r.compat, r.icicle, results, newIntents, !andResume, + System.identityHashCode(r), r.info, mService.mConfiguration, + r.compat, r.icicle, results, newIntents, !andResume, mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop); @@ -4035,7 +4035,18 @@ final class ActivityStack { // But then we need to figure out how it needs to deal with that. Configuration oldConfig = r.configuration; r.configuration = newConfig; - + + // Determine what has changed. May be nothing, if this is a config + // that has come back from the app after going idle. In that case + // we just want to leave the official config object now in the + // activity and do nothing else. + final int changes = oldConfig.diff(newConfig); + if (changes == 0 && !r.forceNewConfig) { + if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG, + "Configuration no differences in " + r); + return true; + } + // If the activity isn't currently running, just leave the new // configuration and it will pick that up next time it starts. if (r.app == null || r.app.thread == null) { @@ -4046,8 +4057,7 @@ final class ActivityStack { return true; } - // Figure out what has changed between the two configurations. - int changes = oldConfig.diff(newConfig); + // Figure out how to handle the changes between the configurations. if (DEBUG_SWITCH || DEBUG_CONFIGURATION) { Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x" + Integer.toHexString(changes) + ", handles=0x" diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 0da5cc631e41..e6107826aa8c 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -85,7 +85,6 @@ import android.net.NetworkIdentity; import android.net.NetworkPolicy; import android.net.NetworkQuotaInfo; import android.net.NetworkState; -import android.net.NetworkStats; import android.net.NetworkTemplate; import android.os.Binder; import android.os.Environment; @@ -489,7 +488,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final long end = currentTime; final long totalBytes = getTotalBytes(policy.template, start, end); - if (policy.limitBytes != LIMIT_DISABLED && totalBytes >= policy.limitBytes) { + if (policy.isOverLimit(totalBytes)) { if (policy.lastSnooze >= start) { enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes); } else { @@ -574,7 +573,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final CharSequence title = res.getText(R.string.data_usage_warning_title); final CharSequence body = res.getString(R.string.data_usage_warning_body); - builder.setSmallIcon(R.drawable.ic_menu_info_details); + builder.setSmallIcon(R.drawable.stat_notify_error); builder.setTicker(title); builder.setContentTitle(title); builder.setContentText(body); @@ -606,7 +605,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { break; } - builder.setSmallIcon(com.android.internal.R.drawable.ic_menu_block); + builder.setSmallIcon(R.drawable.stat_notify_disabled); builder.setTicker(title); builder.setContentTitle(title); builder.setContentText(body); @@ -640,7 +639,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { break; } - builder.setSmallIcon(R.drawable.ic_menu_info_details); + builder.setSmallIcon(R.drawable.stat_notify_error); builder.setTicker(title); builder.setContentTitle(title); builder.setContentText(body); @@ -677,7 +676,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { builder.setOnlyAlertOnce(true); builder.setOngoing(true); - builder.setSmallIcon(R.drawable.ic_menu_info_details); + builder.setSmallIcon(R.drawable.stat_notify_error); builder.setTicker(title); builder.setContentTitle(title); builder.setContentText(body); @@ -750,8 +749,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final long totalBytes = getTotalBytes(policy.template, start, end); // disable data connection when over limit and not snoozed - final boolean overLimit = policy.limitBytes != LIMIT_DISABLED - && totalBytes > policy.limitBytes && policy.lastSnooze < start; + final boolean overLimit = policy.isOverLimit(totalBytes) && policy.lastSnooze < start; final boolean enabled = !overLimit; setNetworkTemplateEnabled(policy.template, enabled); @@ -1535,10 +1533,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private long getTotalBytes(NetworkTemplate template, long start, long end) { try { - final NetworkStats stats = mNetworkStats.getSummaryForNetwork( - template, start, end); - final NetworkStats.Entry entry = stats.getValues(0, null); - return entry.rxBytes + entry.txBytes; + return mNetworkStats.getSummaryForNetwork(template, start, end).getTotalBytes(); } catch (RemoteException e) { // ignored; service lives in system_server return 0; diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 19dd606fe188..0e9f64c34480 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -1157,6 +1157,10 @@ public class PackageManagerService extends IPackageManager.Stub { } // synchronized (mInstallLock) } + public boolean isFirstBoot() { + return !mRestoredSettings; + } + private String getRequiredVerifierLPr() { final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, @@ -2983,12 +2987,14 @@ public class PackageManagerService extends IPackageManager.Stub { } if (pkgs != null) { for (int i=0; i<pkgs.size(); i++) { - try { - ActivityManagerNative.getDefault().showBootMessage( - mContext.getResources().getString( - com.android.internal.R.string.android_upgrading_apk, - i+1, pkgs.size()), true); - } catch (RemoteException e) { + if (!isFirstBoot()) { + try { + ActivityManagerNative.getDefault().showBootMessage( + mContext.getResources().getString( + com.android.internal.R.string.android_upgrading_apk, + i+1, pkgs.size()), true); + } catch (RemoteException e) { + } } PackageParser.Package p = pkgs.get(i); synchronized (mInstallLock) { diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index 7cdb5b15ba31..bfe6613cf630 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -1238,9 +1238,8 @@ final class Settings { mReadMessages.append("No start tag found in settings file\n"); PackageManagerService.reportSettingsProblem(Log.WARN, "No start tag found in package manager settings"); - Log - .wtf(PackageManagerService.TAG, - "No start tag found in package manager settings"); + Log.wtf(PackageManagerService.TAG, + "No start tag found in package manager settings"); return false; } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 73a96013358a..06a6e9892dfc 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -297,6 +297,8 @@ public class WindowManagerService extends IWindowManager.Stub final boolean mHaveInputMethods; + final boolean mAllowBootMessages; + final boolean mLimitedAlphaCompositing; final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager(); @@ -633,8 +635,8 @@ public class WindowManagerService extends IWindowManager.Stub float mCompatibleScreenScale; public static WindowManagerService main(Context context, - PowerManagerService pm, boolean haveInputMethods) { - WMThread thr = new WMThread(context, pm, haveInputMethods); + PowerManagerService pm, boolean haveInputMethods, boolean allowBootMsgs) { + WMThread thr = new WMThread(context, pm, haveInputMethods, allowBootMsgs); thr.start(); synchronized (thr) { @@ -654,19 +656,21 @@ public class WindowManagerService extends IWindowManager.Stub private final Context mContext; private final PowerManagerService mPM; private final boolean mHaveInputMethods; + private final boolean mAllowBootMessages; public WMThread(Context context, PowerManagerService pm, - boolean haveInputMethods) { + boolean haveInputMethods, boolean allowBootMsgs) { super("WindowManager"); mContext = context; mPM = pm; mHaveInputMethods = haveInputMethods; + mAllowBootMessages = allowBootMsgs; } public void run() { Looper.prepare(); WindowManagerService s = new WindowManagerService(mContext, mPM, - mHaveInputMethods); + mHaveInputMethods, mAllowBootMessages); android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_DISPLAY); android.os.Process.setCanSelfBackground(false); @@ -728,9 +732,10 @@ public class WindowManagerService extends IWindowManager.Stub } private WindowManagerService(Context context, PowerManagerService pm, - boolean haveInputMethods) { + boolean haveInputMethods, boolean showBootMsgs) { mContext = context; mHaveInputMethods = haveInputMethods; + mAllowBootMessages = showBootMsgs; mLimitedAlphaCompositing = context.getResources().getBoolean( com.android.internal.R.bool.config_sf_limitedAlpha); @@ -4846,6 +4851,9 @@ public class WindowManagerService extends IWindowManager.Stub public void showBootMessage(final CharSequence msg, final boolean always) { boolean first = false; synchronized(mWindowMap) { + if (!mAllowBootMessages) { + return; + } if (!mShowingBootMessages) { if (!always) { return; diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 51eb0a376d06..dab070567a29 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -22,6 +22,9 @@ LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES ifeq ($(TARGET_BOARD_PLATFORM), omap3) LOCAL_CFLAGS += -DNO_RGBX_8888 endif +ifeq ($(TARGET_BOARD_PLATFORM), omap4) + LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY +endif ifeq ($(TARGET_BOARD_PLATFORM), s5pc110) LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE endif diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp index 59b7e5a7413b..3b7c09e80a83 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp @@ -122,7 +122,7 @@ status_t DisplayHardwareBase::DisplayEventThread::initCheck() const DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger, uint32_t displayIndex) - : mCanDraw(true), mScreenAcquired(true) + : mScreenAcquired(true) { mDisplayEventThread = new DisplayEventThread(flinger); } @@ -133,14 +133,9 @@ DisplayHardwareBase::~DisplayHardwareBase() mDisplayEventThread->requestExitAndWait(); } -void DisplayHardwareBase::setCanDraw(bool canDraw) -{ - mCanDraw = canDraw; -} - bool DisplayHardwareBase::canDraw() const { - return mCanDraw && mScreenAcquired; + return mScreenAcquired; } void DisplayHardwareBase::releaseScreen() const diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h index 3ebc7b6cc54d..ef2df432ce18 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h @@ -43,7 +43,6 @@ public: bool isScreenAcquired() const; bool canDraw() const; - void setCanDraw(bool canDraw); private: @@ -74,7 +73,6 @@ private: }; sp<DisplayEventThreadBase> mDisplayEventThread; - mutable int mCanDraw; mutable int mScreenAcquired; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b01a6a34d16b..195ad2eae498 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -84,7 +84,6 @@ SurfaceFlinger::SurfaceFlinger() mBootTime(systemTime()), mVisibleRegionsDirty(false), mHwWorkListDirty(false), - mDeferReleaseConsole(false), mFreezeDisplay(false), mElectronBeamAnimationMode(0), mFreezeCount(0), @@ -503,17 +502,9 @@ void SurfaceFlinger::handleConsoleEvents() SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode); } - if (mDeferReleaseConsole && hw.isScreenAcquired()) { - // We got the release signal before the acquire signal - mDeferReleaseConsole = false; - hw.releaseScreen(); - } - if (what & eConsoleReleased) { if (hw.isScreenAcquired()) { hw.releaseScreen(); - } else { - mDeferReleaseConsole = true; } } @@ -1814,6 +1805,8 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, // redraw the screen entirely... glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { @@ -1845,7 +1838,7 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() const DisplayHardware& hw(graphicPlane(0).displayHardware()); const uint32_t hw_w = hw.getWidth(); const uint32_t hw_h = hw.getHeight(); - const Region screenBounds(hw.bounds()); + const Region screenBounds(hw.getBounds()); GLfloat u, v; GLuint tname; @@ -1855,7 +1848,7 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() } GLfloat vtx[8]; - const GLfloat texCoords[4][2] = { {0,1}, {0,1-v}, {u,1-v}, {u,1} }; + const GLfloat texCoords[4][2] = { {0,0}, {0,v}, {u,v}, {u,0} }; glBindTexture(GL_TEXTURE_2D, tname); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -1941,6 +1934,12 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() s_curve_interpolator itb(nbFrames, 8.5f); v_stretch vverts(hw_w, hw_h); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); for (int i=0 ; i<nbFrames ; i++) { @@ -2169,7 +2168,6 @@ status_t SurfaceFlinger::turnElectronBeamOffImplLocked(int32_t mode) glEnable(GL_SCISSOR_TEST); hw.flip( Region(hw.bounds()) ); - hw.setCanDraw(false); return NO_ERROR; } @@ -2218,7 +2216,6 @@ status_t SurfaceFlinger::turnElectronBeamOnImplLocked(int32_t mode) if (mode & ISurfaceComposer::eElectronBeamAnimationOn) { electronBeamOnAnimationImplLocked(); } - hw.setCanDraw(true); // make sure to redraw the whole screen when the animation is done mDirtyRegion.set(hw.bounds()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 92b265ec8e2c..1cb9be28acf4 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -363,7 +363,6 @@ private: Region mWormholeRegion; bool mVisibleRegionsDirty; bool mHwWorkListDirty; - bool mDeferReleaseConsole; bool mFreezeDisplay; int32_t mElectronBeamAnimationMode; int32_t mFreezeCount; diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index dded39e1a6a3..fe41e7e61b0c 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -88,6 +88,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { PendingIntent intent = tracker.mDeliveryIntent; Intent fillIn = new Intent(); fillIn.putExtra("pdu", sms.getPdu()); + fillIn.putExtra("format", android.telephony.SmsMessage.FORMAT_3GPP2); try { intent.send(mContext, Activity.RESULT_OK, fillIn); } catch (CanceledException ex) {} diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java index 4e1cc9afd13f..c1553d831c9b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -122,6 +122,7 @@ public final class GsmSMSDispatcher extends SMSDispatcher { PendingIntent intent = tracker.mDeliveryIntent; Intent fillIn = new Intent(); fillIn.putExtra("pdu", IccUtils.hexStringToBytes(pduString)); + fillIn.putExtra("format", android.telephony.SmsMessage.FORMAT_3GPP); try { intent.send(mContext, Activity.RESULT_OK, fillIn); } catch (CanceledException ex) {} diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java index b63ff3dca8df..e0ce3228c75b 100644 --- a/test-runner/src/android/test/mock/MockContentProvider.java +++ b/test-runner/src/android/test/mock/MockContentProvider.java @@ -21,16 +21,12 @@ import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentValues; import android.content.Context; -import android.content.EntityIterator; import android.content.IContentProvider; import android.content.OperationApplicationException; import android.content.pm.PathPermission; import android.content.pm.ProviderInfo; import android.content.res.AssetFileDescriptor; import android.database.Cursor; -import android.database.CursorWindow; -import android.database.IBulkCursor; -import android.database.IContentObserver; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; @@ -55,84 +51,75 @@ public class MockContentProvider extends ContentProvider { * IContentProvider that directs all calls to this MockContentProvider. */ private class InversionIContentProvider implements IContentProvider { - @SuppressWarnings("unused") + @Override public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws RemoteException, OperationApplicationException { return MockContentProvider.this.applyBatch(operations); } - @SuppressWarnings("unused") + @Override public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException { return MockContentProvider.this.bulkInsert(url, initialValues); } - @SuppressWarnings("unused") - public IBulkCursor bulkQuery(Uri url, String[] projection, String selection, - String[] selectionArgs, String sortOrder, IContentObserver observer, - CursorWindow window) throws RemoteException { - throw new UnsupportedOperationException("Must not come here"); - } - - @SuppressWarnings("unused") + @Override public int delete(Uri url, String selection, String[] selectionArgs) throws RemoteException { return MockContentProvider.this.delete(url, selection, selectionArgs); } - @SuppressWarnings("unused") + @Override public String getType(Uri url) throws RemoteException { return MockContentProvider.this.getType(url); } - @SuppressWarnings("unused") + @Override public Uri insert(Uri url, ContentValues initialValues) throws RemoteException { return MockContentProvider.this.insert(url, initialValues); } - @SuppressWarnings("unused") + @Override public AssetFileDescriptor openAssetFile(Uri url, String mode) throws RemoteException, FileNotFoundException { return MockContentProvider.this.openAssetFile(url, mode); } - @SuppressWarnings("unused") + @Override public ParcelFileDescriptor openFile(Uri url, String mode) throws RemoteException, FileNotFoundException { return MockContentProvider.this.openFile(url, mode); } - @SuppressWarnings("unused") + @Override public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder) throws RemoteException { return MockContentProvider.this.query(url, projection, selection, selectionArgs, sortOrder); } - @SuppressWarnings("unused") + @Override public int update(Uri url, ContentValues values, String selection, String[] selectionArgs) throws RemoteException { return MockContentProvider.this.update(url, values, selection, selectionArgs); } - /** - * @hide - */ - @SuppressWarnings("unused") + @Override public Bundle call(String method, String request, Bundle args) throws RemoteException { return MockContentProvider.this.call(method, request, args); } + @Override public IBinder asBinder() { throw new UnsupportedOperationException(); } - @SuppressWarnings("unused") + @Override public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException { return MockContentProvider.this.getStreamTypes(url, mimeTypeFilter); } - @SuppressWarnings("unused") + @Override public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts) throws RemoteException, FileNotFoundException { return MockContentProvider.this.openTypedAssetFile(url, mimeType, opts); diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java index 183be415880c..b7733a4d55eb 100644 --- a/test-runner/src/android/test/mock/MockIContentProvider.java +++ b/test-runner/src/android/test/mock/MockIContentProvider.java @@ -23,9 +23,6 @@ import android.content.EntityIterator; import android.content.IContentProvider; import android.content.res.AssetFileDescriptor; import android.database.Cursor; -import android.database.CursorWindow; -import android.database.IBulkCursor; -import android.database.IContentObserver; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; @@ -47,12 +44,6 @@ public class MockIContentProvider implements IContentProvider { throw new UnsupportedOperationException("unimplemented mock method"); } - public IBulkCursor bulkQuery(Uri url, String[] projection, String selection, - String[] selectionArgs, String sortOrder, IContentObserver observer, - CursorWindow window) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - @SuppressWarnings("unused") public int delete(Uri url, String selection, String[] selectionArgs) throws RemoteException { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java index 3835378b5da0..c91a3bf91c51 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java @@ -23,9 +23,6 @@ import android.content.IContentProvider; import android.content.OperationApplicationException; import android.content.res.AssetFileDescriptor; import android.database.Cursor; -import android.database.CursorWindow; -import android.database.IBulkCursor; -import android.database.IContentObserver; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; @@ -41,78 +38,84 @@ import java.util.ArrayList; * TODO: never return null when the method is not supposed to. Return fake data instead. */ public final class BridgeContentProvider implements IContentProvider { - + @Override public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> arg0) throws RemoteException, OperationApplicationException { // TODO Auto-generated method stub return null; } + @Override public int bulkInsert(Uri arg0, ContentValues[] arg1) throws RemoteException { // TODO Auto-generated method stub return 0; } - public IBulkCursor bulkQuery(Uri arg0, String[] arg1, String arg2, String[] arg3, - String arg4, IContentObserver arg5, CursorWindow arg6) throws RemoteException { - // TODO Auto-generated method stub - return null; - } - + @Override public Bundle call(String arg0, String arg1, Bundle arg2) throws RemoteException { // TODO Auto-generated method stub return null; } + @Override public int delete(Uri arg0, String arg1, String[] arg2) throws RemoteException { // TODO Auto-generated method stub return 0; } + @Override public String getType(Uri arg0) throws RemoteException { // TODO Auto-generated method stub return null; } + @Override public Uri insert(Uri arg0, ContentValues arg1) throws RemoteException { // TODO Auto-generated method stub return null; } + @Override public AssetFileDescriptor openAssetFile(Uri arg0, String arg1) throws RemoteException, FileNotFoundException { // TODO Auto-generated method stub return null; } + @Override public ParcelFileDescriptor openFile(Uri arg0, String arg1) throws RemoteException, FileNotFoundException { // TODO Auto-generated method stub return null; } + @Override public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) throws RemoteException { // TODO Auto-generated method stub return null; } + @Override public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) throws RemoteException { // TODO Auto-generated method stub return 0; } + @Override public IBinder asBinder() { // TODO Auto-generated method stub return null; } + @Override public String[] getStreamTypes(Uri arg0, String arg1) throws RemoteException { // TODO Auto-generated method stub return null; } + @Override public AssetFileDescriptor openTypedAssetFile(Uri arg0, String arg1, Bundle arg2) throws RemoteException, FileNotFoundException { // TODO Auto-generated method stub |