diff options
133 files changed, 2067 insertions, 6673 deletions
diff --git a/api/current.txt b/api/current.txt index d3333f0..86339f2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -15750,6 +15750,7 @@ package android.provider { public static final class ContactsContract.CommonDataKinds.Photo implements android.provider.ContactsContract.DataColumnsWithJoins { field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo"; field public static final java.lang.String PHOTO = "data15"; + field public static final java.lang.String PHOTO_FILE_ID = "data14"; } public static final class ContactsContract.CommonDataKinds.Relation implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { @@ -15889,7 +15890,9 @@ package android.provider { public static final class ContactsContract.Contacts.Photo implements android.provider.BaseColumns android.provider.ContactsContract.DataColumnsWithJoins { field public static final java.lang.String CONTENT_DIRECTORY = "photo"; + field public static final java.lang.String DISPLAY_PHOTO = "display_photo"; field public static final java.lang.String PHOTO = "data15"; + field public static final java.lang.String PHOTO_FILE_ID = "data14"; } public static final class ContactsContract.Contacts.StreamItems implements android.provider.ContactsContract.StreamItemsColumns { @@ -15902,6 +15905,7 @@ package android.provider { field public static final java.lang.String IN_VISIBLE_GROUP = "in_visible_group"; field public static final java.lang.String IS_USER_PROFILE = "is_user_profile"; field public static final java.lang.String LOOKUP_KEY = "lookup"; + field public static final java.lang.String PHOTO_FILE_ID = "photo_file_id"; field public static final java.lang.String PHOTO_ID = "photo_id"; field public static final java.lang.String PHOTO_THUMBNAIL_URI = "photo_thumb_uri"; field public static final java.lang.String PHOTO_URI = "photo_uri"; @@ -15990,6 +15994,13 @@ package android.provider { field public static final int UNDEFINED = 0; // 0x0 } + public static final class ContactsContract.DisplayPhoto { + field public static final android.net.Uri CONTENT_MAX_DIMENSIONS_URI; + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String DISPLAY_MAX_DIM = "display_max_dim"; + field public static final java.lang.String THUMBNAIL_MAX_DIM = "thumbnail_max_dim"; + } + public static abstract interface ContactsContract.FullNameStyle { field public static final int CHINESE = 3; // 0x3 field public static final int CJK = 2; // 0x2 @@ -16008,6 +16019,8 @@ package android.provider { } protected static abstract interface ContactsContract.GroupsColumns { + field public static final java.lang.String ACTION = "action"; + field public static final java.lang.String ACTION_URI = "action_uri"; field public static final java.lang.String AUTO_ADD = "auto_add"; field public static final java.lang.String DATA_SET = "data_set"; field public static final java.lang.String DELETED = "deleted"; @@ -16125,6 +16138,10 @@ package android.provider { field public static final java.lang.String CONTENT_DIRECTORY = "data"; } + public static final class ContactsContract.RawContacts.DisplayPhoto { + field public static final java.lang.String CONTENT_DIRECTORY = "display_photo"; + } + public static final class ContactsContract.RawContacts.Entity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns { field public static final java.lang.String CONTENT_DIRECTORY = "entity"; field public static final java.lang.String DATA_ID = "data_id"; @@ -26082,7 +26099,7 @@ package android.widget { ctor public ShareActionProvider(android.content.Context); method public android.view.View onCreateActionView(); method public void setShareHistoryFileName(java.lang.String); - method public void setShareIntent(android.view.View, android.content.Intent); + method public void setShareIntent(android.content.Intent); field public static final java.lang.String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml"; } diff --git a/cmds/system_server/system_main.cpp b/cmds/system_server/system_main.cpp index 543f650..d67329d 100644 --- a/cmds/system_server/system_main.cpp +++ b/cmds/system_server/system_main.cpp @@ -52,10 +52,5 @@ int main(int argc, const char* const argv[]) LOGW("*** Current priority: %d\n", getpriority(PRIO_PROCESS, 0)); setpriority(PRIO_PROCESS, 0, -1); - #if HAVE_ANDROID_OS - //setgid(GID_SYSTEM); - //setuid(UID_SYSTEM); - #endif - system_init(); } diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index dce0a97..436fdf8 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -28,6 +28,7 @@ import android.os.RemoteException; import android.util.Log; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.util.HashSet; import java.util.LinkedList; @@ -533,6 +534,16 @@ public abstract class BackupAgent extends ContextWrapper { Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex); throw ex; } finally { + // Send the EOD marker indicating that there is no more data + // forthcoming from this agent. + try { + FileOutputStream out = new FileOutputStream(data.getFileDescriptor()); + byte[] buf = new byte[4]; + out.write(buf); + } catch (IOException e) { + Log.e(TAG, "Unable to finalize backup stream!"); + } + Binder.restoreCallingIdentity(ident); try { callbackBinder.opComplete(token); diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java index 60900e1..2c4b863 100644 --- a/core/java/android/os/storage/StorageVolume.java +++ b/core/java/android/os/storage/StorageVolume.java @@ -172,7 +172,10 @@ public class StorageVolume implements Parcelable { @Override public String toString() { - return mPath; + return "StorageVolume [mAllowMassStorage=" + mAllowMassStorage + ", mDescription=" + + mDescription + ", mEmulated=" + mEmulated + ", mMaxFileSize=" + mMaxFileSize + + ", mMtpReserveSpace=" + mMtpReserveSpace + ", mPath=" + mPath + ", mRemovable=" + + mRemovable + ", mStorageId=" + mStorageId + "]"; } public static final Parcelable.Creator<StorageVolume> CREATOR = diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index ec67683..0dd9a4d 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -17,6 +17,7 @@ package android.provider; import android.accounts.Account; +import android.app.Activity; import android.content.ContentProviderClient; import android.content.ContentProviderOperation; import android.content.ContentResolver; @@ -749,11 +750,25 @@ public final class ContactsContract { public static final String PHOTO_ID = "photo_id"; /** + * Photo file ID of the full-size photo. If present, this will be used to populate + * {@link #PHOTO_URI}. The ID can also be used with + * {@link ContactsContract.DisplayPhoto#CONTENT_URI} to create a URI to the photo. + * If this is present, {@link #PHOTO_ID} is also guaranteed to be populated. + * + * <P>Type: INTEGER</P> + */ + public static final String PHOTO_FILE_ID = "photo_file_id"; + + /** * A URI that can be used to retrieve the contact's full-size photo. + * If PHOTO_FILE_ID is not null, this will be populated with a URI based off + * {@link ContactsContract.DisplayPhoto#CONTENT_URI}. Otherwise, this will + * be populated with the same value as {@link #PHOTO_THUMBNAIL_URI}. * A photo can be referred to either by a URI (this field) or by ID - * (see {@link #PHOTO_ID}). If PHOTO_ID is not null, PHOTO_URI and - * PHOTO_THUMBNAIL_URI shall not be null (but not necessarily vice versa). - * Thus using PHOTO_URI is a more robust method of retrieving contact photos. + * (see {@link #PHOTO_ID}). If either PHOTO_FILE_ID or PHOTO_ID is not null, + * PHOTO_URI and PHOTO_THUMBNAIL_URI shall not be null (but not necessarily + * vice versa). Thus using PHOTO_URI is a more robust method of retrieving + * contact photos. * * <P>Type: TEXT</P> */ @@ -766,7 +781,7 @@ public final class ContactsContract { * PHOTO_THUMBNAIL_URI shall not be null (but not necessarily vice versa). * If the content provider does not differentiate between full-size photos * and thumbnail photos, PHOTO_THUMBNAIL_URI and {@link #PHOTO_URI} can contain - * the same value, but either both shell be null or both not null. + * the same value, but either both shall be null or both not null. * * <P>Type: TEXT</P> */ @@ -1690,10 +1705,15 @@ public final class ContactsContract { /** * A <i>read-only</i> sub-directory of a single contact that contains - * the contact's primary photo. + * the contact's primary photo. The photo may be stored in up to two ways - + * the default "photo" is a thumbnail-sized image stored directly in the data + * row, while the "display photo", if present, is a larger version stored as + * a file. * <p> * Usage example: - * + * <dl> + * <dt>Retrieving the thumbnail-sized photo</dt> + * <dd> * <pre> * public InputStream openPhoto(long contactId) { * Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); @@ -1716,10 +1736,29 @@ public final class ContactsContract { * return null; * } * </pre> + * </dd> + * <dt>Retrieving the larger photo version</dt> + * <dd> + * <pre> + * public InputStream openDisplayPhoto(long contactId) { + * Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); + * Uri displayPhotoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.DISPLAY_PHOTO); + * try { + * AssetFileDescriptor fd = + * getContentResolver().openAssetFile(displayPhotoUri, "r"); + * return fd.createInputStream(); + * } catch (FileNotFoundException e) { + * return null; + * } + * } + * </pre> + * </dd> + * </dl> * * </p> - * <p>You should also consider using the convenience method + * <p>You may also consider using the convenience method * {@link ContactsContract.Contacts#openContactPhotoInputStream(ContentResolver, Uri)} + * to retrieve the raw photo contents of the thumbnail-sized photo. * </p> * <p> * This directory can be used either with a {@link #CONTENT_URI} or @@ -1738,6 +1777,19 @@ public final class ContactsContract { public static final String CONTENT_DIRECTORY = "photo"; /** + * The directory twig for retrieving the full-size display photo. + */ + public static final String DISPLAY_PHOTO = "display_photo"; + + /** + * Full-size photo file ID of the raw contact. + * See {@link ContactsContract.DisplayPhoto}. + * <p> + * Type: NUMBER + */ + public static final String PHOTO_FILE_ID = DATA14; + + /** * Thumbnail photo of the raw contact. This is the raw bytes of an image * that could be inflated using {@link android.graphics.BitmapFactory}. * <p> @@ -2498,6 +2550,56 @@ public final class ContactsContract { } /** + * <p> + * A sub-directory of a single raw contact that represents its primary + * display photo. To access this directory append + * {@link RawContacts.DisplayPhoto#CONTENT_DIRECTORY} to the raw contact URI. + * The resulting URI represents an image file, and should be interacted with + * using ContentProvider.openAssetFile. + * <p> + * <p> + * Note that this sub-directory also supports opening the photo as an asset file + * in write mode. Callers can create or replace the primary photo associated + * with this raw contact by opening the asset file and writing the full-size + * photo contents into it. When the file is closed, the image will be parsed, + * sized down if necessary for the full-size display photo and thumbnail + * dimensions, and stored. + * </p> + * <p> + * Usage example: + * <pre> + * public void writeDisplayPhoto(long rawContactId, byte[] photo) { + * Uri rawContactPhotoUri = Uri.withAppendedPath( + * ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), + * RawContacts.DisplayPhoto.CONTENT_DIRECTORY); + * try { + * AssetFileDescriptor fd = + * getContentResolver().openAssetFile(rawContactPhotoUri, "rw"); + * OutputStream os = fd.createOutputStream(); + * os.write(photo); + * os.close(); + * fd.close(); + * } catch (IOException e) { + * // Handle error cases. + * } + * } + * </pre> + * </p> + */ + public static final class DisplayPhoto { + /** + * No public constructor since this is a utility class + */ + private DisplayPhoto() { + } + + /** + * The directory twig for this sub-table + */ + public static final String CONTENT_DIRECTORY = "display_photo"; + } + + /** * TODO: javadoc * @param cursor * @return @@ -3192,6 +3294,50 @@ public final class ContactsContract { } /** + * <p> + * Constants for the photo files table, which tracks metadata for hi-res photos + * stored in the file system. + * </p> + * + * @hide + */ + public static final class PhotoFiles implements BaseColumns, PhotoFilesColumns { + /** + * No public constructor since this is a utility class + */ + private PhotoFiles() { + } + } + + /** + * Columns in the PhotoFiles table. + * + * @see ContactsContract.PhotoFiles + * + * @hide + */ + protected interface PhotoFilesColumns { + + /** + * The height, in pixels, of the photo this entry is associated with. + * <P>Type: NUMBER</P> + */ + public static final String HEIGHT = "height"; + + /** + * The width, in pixels, of the photo this entry is associated with. + * <P>Type: NUMBER</P> + */ + public static final String WIDTH = "width"; + + /** + * The size, in bytes, of the photo stored on disk. + * <P>Type: NUMBER</P> + */ + public static final String FILESIZE = "filesize"; + } + + /** * Columns in the Data table. * * @see ContactsContract.Data @@ -5891,7 +6037,7 @@ public final class ContactsContract { /** * <p> - * A data kind representing an photo for the contact. + * A data kind representing a photo for the contact. * </p> * <p> * Some sync adapters will choose to download photos in a separate @@ -5911,10 +6057,17 @@ public final class ContactsContract { * <th>Alias</th><th colspan='2'>Data column</th> * </tr> * <tr> + * <td>NUMBER</td> + * <td>{@link #PHOTO_FILE_ID}</td> + * <td>{@link #DATA14}</td> + * <td>ID of the hi-res photo file.</td> + * </tr> + * <tr> * <td>BLOB</td> * <td>{@link #PHOTO}</td> * <td>{@link #DATA15}</td> - * <td>By convention, binary data is stored in DATA15.</td> + * <td>By convention, binary data is stored in DATA15. The thumbnail of the + * photo is stored in this column.</td> * </tr> * </table> */ @@ -5928,6 +6081,14 @@ public final class ContactsContract { public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo"; /** + * Photo file ID for the display photo of the raw contact. + * See {@link ContactsContract.DisplayPhoto}. + * <p> + * Type: NUMBER + */ + public static final String PHOTO_FILE_ID = DATA14; + + /** * Thumbnail photo of the raw contact. This is the raw bytes of an image * that could be inflated using {@link android.graphics.BitmapFactory}. * <p> @@ -6251,6 +6412,28 @@ public final class ContactsContract { public static final String NOTES = "notes"; /** + * The Activity action to open the group in the source app (e.g. + * {@link Intent#ACTION_VIEW}). Can be NULL if the group does not have a dedicated viewer. + * This is used in conjunction with {@link #ACTION_URI}: In order to show an "Open in + * (sourceapp)"-button, both of these fields must be set + * <p> + * Type: TEXT + */ + public static final String ACTION = "action"; + + + /** + * Uri to open the group in the source app. + * Can be NULL if the group does not have a dedicated viewer. + * This is used in conjunction with {@link #ACTION}: In order to show an "Open in + * (sourceapp)"-button, both of these fields must be set + * <p> + * Type: TEXT + */ + public static final String ACTION_URI = "action_uri"; + + + /** * The ID of this group if it is a System Group, i.e. a group that has a special meaning * to the sync adapter, null otherwise. * <P>Type: TEXT</P> @@ -7047,6 +7230,66 @@ public final class ContactsContract { } /** + * Helper class for accessing full-size photos by photo file ID. + * <p> + * Usage example: + * <dl> + * <dt>Retrieving a full-size photo by photo file ID (see + * {@link ContactsContract.ContactsColumns#PHOTO_FILE_ID}) + * </dt> + * <dd> + * <pre> + * public InputStream openDisplayPhoto(long photoFileId) { + * Uri displayPhotoUri = ContentUris.withAppendedId(DisplayPhoto.CONTENT_URI, photoKey); + * try { + * AssetFileDescriptor fd = getContentResolver().openAssetFile(displayPhotoUri, "r"); + * return fd.createInputStream(); + * } catch (FileNotFoundException e) { + * return null; + * } + * } + * </pre> + * </dd> + * </dl> + * </p> + */ + public static final class DisplayPhoto { + /** + * no public constructor since this is a utility class + */ + private DisplayPhoto() {} + + /** + * The content:// style URI for this class, which allows access to full-size photos, + * given a key. + */ + public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "display_photo"); + + /** + * This URI allows the caller to query for the maximum dimensions of a display photo + * or thumbnail. Requests to this URI can be performed on the UI thread because + * they are always unblocking. + */ + public static final Uri CONTENT_MAX_DIMENSIONS_URI = + Uri.withAppendedPath(AUTHORITY_URI, "photo_dimensions"); + + /** + * Queries to {@link ContactsContract.DisplayPhoto#CONTENT_MAX_DIMENSIONS_URI} will + * contain this column, populated with the maximum height and width (in pixels) + * that will be stored for a display photo. Larger photos will be down-sized to + * fit within a square of this many pixels. + */ + public static final String DISPLAY_MAX_DIM = "display_max_dim"; + + /** + * Queries to {@link ContactsContract.DisplayPhoto#CONTENT_MAX_DIMENSIONS_URI} will + * contain this column, populated with the height and width (in pixels) for photo + * thumbnails. + */ + public static final String THUMBNAIL_MAX_DIM = "thumbnail_max_dim"; + } + + /** * Contains helper classes used to create or manage {@link android.content.Intent Intents} * that involve contacts. */ diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 8e4725f..32ca226 100755 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -181,7 +181,7 @@ public class TextToSpeech { * * @hide * @deprecated No longer in use, the default engine is determined by - * the sort order defined in {@link EngineInfoComparator}. Note that + * the sort order defined in {@link TtsEngines}. Note that * this doesn't "break" anything because there is no guarantee that * the engine specified below is installed on a given build, let * alone be the default. @@ -504,36 +504,39 @@ public class TextToSpeech { } private int initTts() { - String defaultEngine = getDefaultEngine(); - String engine = defaultEngine; - if (mEnginesHelper.isEngineInstalled(mRequestedEngine)) { - engine = mRequestedEngine; - } - - // Try requested engine - if (connectToEngine(engine)) { - mCurrentEngine = engine; - return SUCCESS; + // Step 1: Try connecting to the engine that was requested. + if (mRequestedEngine != null && mEnginesHelper.isEngineInstalled(mRequestedEngine)) { + if (connectToEngine(mRequestedEngine)) { + mCurrentEngine = mRequestedEngine; + return SUCCESS; + } } - // Fall back to user's default engine if different from the already tested one - if (!engine.equals(defaultEngine)) { + // Step 2: Try connecting to the user's default engine. + final String defaultEngine = getDefaultEngine(); + if (defaultEngine != null && !defaultEngine.equals(mRequestedEngine)) { if (connectToEngine(defaultEngine)) { - mCurrentEngine = engine; + mCurrentEngine = defaultEngine; return SUCCESS; } } + // Step 3: Try connecting to the highest ranked engine in the + // system. final String highestRanked = mEnginesHelper.getHighestRankedEngineName(); - // Fall back to the hardcoded default if different from the two above - if (!defaultEngine.equals(highestRanked) - && !engine.equals(highestRanked)) { + if (highestRanked != null && !highestRanked.equals(mRequestedEngine) && + !highestRanked.equals(defaultEngine)) { if (connectToEngine(highestRanked)) { - mCurrentEngine = engine; + mCurrentEngine = highestRanked; return SUCCESS; } } + // NOTE: The API currently does not allow the caller to query whether + // they are actually connected to any engine. This might fail for various + // reasons like if the user disables all her TTS engines. + + mCurrentEngine = null; dispatchOnInit(ERROR); return ERROR; } @@ -963,7 +966,7 @@ public class TextToSpeech { /** * Synthesizes the given text to a file using the specified parameters. * - * @param text Thetext that should be synthesized + * @param text The text that should be synthesized * @param params Parameters for the request. Can be null. * Supported parameter names: * {@link Engine#KEY_PARAM_UTTERANCE_ID}. @@ -1073,7 +1076,9 @@ public class TextToSpeech { * * @deprecated This doesn't inform callers when the TTS engine has been * initialized. {@link #TextToSpeech(Context, OnInitListener, String)} - * can be used with the appropriate engine name. + * can be used with the appropriate engine name. Also, there is no + * guarantee that the engine specified will be loaded. If it isn't + * installed or disabled, the user / system wide defaults will apply. * * @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico") * diff --git a/core/java/android/view/ActionProvider.java b/core/java/android/view/ActionProvider.java index 47f7358..5601dc5 100644 --- a/core/java/android/view/ActionProvider.java +++ b/core/java/android/view/ActionProvider.java @@ -28,7 +28,9 @@ import android.content.Context; * {@link android.app.ActionBar} as a substitute for the menu item when the item is * displayed as an action item. Also the provider is responsible for performing a * default action if a menu item placed on the overflow menu of the ActionBar is - * selected and none of the menu item callbacks has handled the selection. + * selected and none of the menu item callbacks has handled the selection. For this + * case the provider can also optionally provide a sub-menu for accomplishing the + * task at hand. * </p> * <p> * There are two ways for using an action provider for creating and handling of action views: diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index 0294e3f..88583df 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -120,6 +120,7 @@ class CallbackProxy extends Handler { private static final int AUTO_LOGIN = 140; private static final int CLIENT_CERT_REQUEST = 141; private static final int SEARCHBOX_IS_SUPPORTED_CALLBACK = 142; + private static final int SEARCHBOX_DISPATCH_COMPLETE_CALLBACK= 143; // Message triggered by the client to resume execution private static final int NOTIFY = 200; @@ -821,6 +822,13 @@ class CallbackProxy extends Handler { searchBox.handleIsSupportedCallback(supported); break; } + case SEARCHBOX_DISPATCH_COMPLETE_CALLBACK: { + SearchBoxImpl searchBox = (SearchBoxImpl) mWebView.getSearchBox(); + Boolean success = (Boolean) msg.obj; + searchBox.handleDispatchCompleteCallback(msg.getData().getString("function"), + msg.getData().getInt("id"), success); + break; + } } } @@ -1641,4 +1649,13 @@ class CallbackProxy extends Handler { msg.obj = new Boolean(isSupported); sendMessage(msg); } + + void onSearchboxDispatchCompleteCallback(String function, int id, boolean success) { + Message msg = obtainMessage(SEARCHBOX_DISPATCH_COMPLETE_CALLBACK); + msg.obj = Boolean.valueOf(success); + msg.getData().putString("function", function); + msg.getData().putInt("id", id); + + sendMessage(msg); + } } diff --git a/core/java/android/webkit/SearchBox.java b/core/java/android/webkit/SearchBox.java index 5075302..6512c4b 100644 --- a/core/java/android/webkit/SearchBox.java +++ b/core/java/android/webkit/SearchBox.java @@ -68,11 +68,15 @@ public interface SearchBox { * Notify the search page of any changes to the searchbox. Such as * a change in the typed query (onchange), the user commiting a given query * (onsubmit), or a change in size of a suggestions dropdown (onresize). + * + * @param listener an optional listener to notify of the success of the operation, + * indicating if the javascript function existed and could be called or not. + * It will be called on the UI thread. */ - void onchange(); - void onsubmit(); - void onresize(); - void oncancel(); + void onchange(SearchBoxListener listener); + void onsubmit(SearchBoxListener listener); + void onresize(SearchBoxListener listener); + void oncancel(SearchBoxListener listener); /** * Add and remove listeners to the given Searchbox. Listeners are notified @@ -91,8 +95,12 @@ public interface SearchBox { * Listeners (if any) will be called on the thread that created the * webview. */ - interface SearchBoxListener { - void onSuggestionsReceived(String query, List<String> suggestions); + public abstract class SearchBoxListener { + public void onSuggestionsReceived(String query, List<String> suggestions) {} + public void onChangeComplete(boolean called) {} + public void onSubmitComplete(boolean called) {} + public void onResizeComplete(boolean called) {} + public void onCancelComplete(boolean called) {} } interface IsSupportedCallback { diff --git a/core/java/android/webkit/SearchBoxImpl.java b/core/java/android/webkit/SearchBoxImpl.java index 61fb2ce..9942d25 100644 --- a/core/java/android/webkit/SearchBoxImpl.java +++ b/core/java/android/webkit/SearchBoxImpl.java @@ -16,10 +16,12 @@ package android.webkit; +import android.text.TextUtils; import android.util.Log; import android.webkit.WebViewCore.EventHub; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import org.json.JSONArray; @@ -69,7 +71,7 @@ final class SearchBoxImpl implements SearchBox { private static final String SET_VERBATIM_SCRIPT = "if (window.chrome && window.chrome.searchBox) {" - + " window.chrome.searchBox.verbatim = %s;" + + " window.chrome.searchBox.verbatim = %1$s;" + "}"; private static final String SET_SELECTION_SCRIPT @@ -89,13 +91,21 @@ final class SearchBoxImpl implements SearchBox { + "}"; private static final String DISPATCH_EVENT_SCRIPT - = "if (window.chrome && window.chrome.searchBox &&" - + " window.chrome.searchBox.on%1$s) { window.chrome.searchBox.on%1$s(); }"; + = "if (window.chrome && window.chrome.searchBox && window.chrome.searchBox.on%1$s) {" + + " window.chrome.searchBox.on%1$s();" + + " window.searchBoxJavaBridge_.dispatchCompleteCallback('%1$s', %2$d, true);" + + "} else {" + + " window.searchBoxJavaBridge_.dispatchCompleteCallback('%1$s', %2$d, false);" + + "}"; + + private static final String EVENT_CHANGE = "change"; + private static final String EVENT_SUBMIT = "submit"; + private static final String EVENT_RESIZE = "resize"; + private static final String EVENT_CANCEL = "cancel"; private static final String IS_SUPPORTED_SCRIPT = "if (window.searchBoxJavaBridge_) {" - + " if (window.chrome && window.chrome.searchBox && " - + " window.chrome.searchBox.onsubmit) {" + + " if (window.chrome && window.chrome.sv) {" + " window.searchBoxJavaBridge_.isSupportedCallback(true);" + " } else {" + " window.searchBoxJavaBridge_.isSupportedCallback(false);" @@ -105,11 +115,14 @@ final class SearchBoxImpl implements SearchBox { private final WebViewCore mWebViewCore; private final CallbackProxy mCallbackProxy; private IsSupportedCallback mSupportedCallback; + private int mNextEventId = 1; + private final HashMap<Integer, SearchBoxListener> mEventCallbacks; SearchBoxImpl(WebViewCore webViewCore, CallbackProxy callbackProxy) { mListeners = new ArrayList<SearchBoxListener>(); mWebViewCore = webViewCore; mCallbackProxy = callbackProxy; + mEventCallbacks = new HashMap<Integer, SearchBoxListener>(); } @Override @@ -141,27 +154,36 @@ final class SearchBoxImpl implements SearchBox { } @Override - public void onchange() { - dispatchEvent("change"); + public void onchange(SearchBoxListener callback) { + dispatchEvent(EVENT_CHANGE, callback); } @Override - public void onsubmit() { - dispatchEvent("submit"); + public void onsubmit(SearchBoxListener callback) { + dispatchEvent(EVENT_SUBMIT, callback); } @Override - public void onresize() { - dispatchEvent("resize"); + public void onresize(SearchBoxListener callback) { + dispatchEvent(EVENT_RESIZE, callback); } @Override - public void oncancel() { - dispatchEvent("cancel"); + public void oncancel(SearchBoxListener callback) { + dispatchEvent(EVENT_CANCEL, callback); } - private void dispatchEvent(String eventName) { - final String js = String.format(DISPATCH_EVENT_SCRIPT, eventName); + private void dispatchEvent(String eventName, SearchBoxListener callback) { + int eventId; + if (callback != null) { + synchronized(this) { + eventId = mNextEventId++; + mEventCallbacks.put(eventId, callback); + } + } else { + eventId = 0; + } + final String js = String.format(DISPATCH_EVENT_SCRIPT, eventName, eventId); dispatchJs(js); } @@ -202,9 +224,35 @@ final class SearchBoxImpl implements SearchBox { } } + // Called by Javascript through the Java bridge. + public void dispatchCompleteCallback(String function, int id, boolean successful) { + mCallbackProxy.onSearchboxDispatchCompleteCallback(function, id, successful); + } + + public void handleDispatchCompleteCallback(String function, int id, boolean successful) { + if (id != 0) { + SearchBoxListener listener; + synchronized(this) { + listener = mEventCallbacks.get(id); + mEventCallbacks.remove(id); + } + if (listener != null) { + if (TextUtils.equals(EVENT_CHANGE, function)) { + listener.onChangeComplete(successful); + } else if (TextUtils.equals(EVENT_SUBMIT, function)) { + listener.onSubmitComplete(successful); + } else if (TextUtils.equals(EVENT_RESIZE, function)) { + listener.onResizeComplete(successful); + } else if (TextUtils.equals(EVENT_CANCEL, function)) { + listener.onCancelComplete(successful); + } + } + } + } + // This is used as a hackish alternative to javascript escaping. // There appears to be no such functionality in the core framework. - private String jsonSerialize(String query) { + private static String jsonSerialize(String query) { JSONStringer stringer = new JSONStringer(); try { stringer.array().value(query).endArray(); diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 7ba86a5..3ae10fe 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -9089,6 +9089,52 @@ public class WebView extends AbsoluteLayout } } + /** + * Begin collecting per-tile profiling data + * + * @hide only used by profiling tests + */ + public void tileProfilingStart() { + nativeTileProfilingStart(); + } + /** + * Return per-tile profiling data + * + * @hide only used by profiling tests + */ + public float tileProfilingStop() { + return nativeTileProfilingStop(); + } + + /** @hide only used by profiling tests */ + public void tileProfilingClear() { + nativeTileProfilingClear(); + } + /** @hide only used by profiling tests */ + public int tileProfilingNumFrames() { + return nativeTileProfilingNumFrames(); + } + /** @hide only used by profiling tests */ + public int tileProfilingNumTilesInFrame(int frame) { + return nativeTileProfilingNumTilesInFrame(frame); + } + /** @hide only used by profiling tests */ + public int tileProfilingGetX(int frame, int tile) { + return nativeTileProfilingGetX(frame, tile); + } + /** @hide only used by profiling tests */ + public int tileProfilingGetY(int frame, int tile) { + return nativeTileProfilingGetY(frame, tile); + } + /** @hide only used by profiling tests */ + public boolean tileProfilingGetReady(int frame, int tile) { + return nativeTileProfilingGetReady(frame, tile); + } + /** @hide only used by profiling tests */ + public int tileProfilingGetLevel(int frame, int tile) { + return nativeTileProfilingGetLevel(frame, tile); + } + private native int nativeCacheHitFramePointer(); private native boolean nativeCacheHitIsPlugin(); private native Rect nativeCacheHitNodeBounds(); @@ -9211,6 +9257,15 @@ public class WebView extends AbsoluteLayout private native void nativeStopGL(); private native Rect nativeSubtractLayers(Rect content); private native int nativeTextGeneration(); + private native void nativeTileProfilingStart(); + private native float nativeTileProfilingStop(); + private native void nativeTileProfilingClear(); + private native int nativeTileProfilingNumFrames(); + private native int nativeTileProfilingNumTilesInFrame(int frame); + private native int nativeTileProfilingGetX(int frame, int tile); + private native int nativeTileProfilingGetY(int frame, int tile); + private native boolean nativeTileProfilingGetReady(int frame, int tile); + private native int nativeTileProfilingGetLevel(int frame, int tile); // Never call this version except by updateCachedTextfield(String) - // we always want to pass in our generation number. private native void nativeUpdateCachedTextfield(String updatedText, diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index c652e55..5414b79 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -248,7 +248,7 @@ public final class WebViewCore { /* Get the BrowserFrame component. This is used for subwindow creation and * is called only from BrowserFrame in the WebCore thread. */ - /* package */ BrowserFrame getBrowserFrame() { + /* package */ synchronized BrowserFrame getBrowserFrame() { return mBrowserFrame; } diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java index 83f80ff..32c44d8 100644 --- a/core/java/android/widget/ActivityChooserModel.java +++ b/core/java/android/widget/ActivityChooserModel.java @@ -126,7 +126,7 @@ public class ActivityChooserModel extends DataSetObservable { */ // This cannot be done by a simple comparator since an Activity weight // is computed from history. Note that Activity implements Comparable. - public void sort(Intent intent, List<Activity> activities, + public void sort(Intent intent, List<ActivityResolveInfo> activities, List<HistoricalRecord> historicalRecords); } @@ -215,7 +215,7 @@ public class ActivityChooserModel extends DataSetObservable { /** * List of activities that can handle the current intent. */ - private final List<Activity> mActivitys = new ArrayList<Activity>(); + private final List<ActivityResolveInfo> mActivites = new ArrayList<ActivityResolveInfo>(); /** * List with historical choice records. @@ -311,9 +311,6 @@ public class ActivityChooserModel extends DataSetObservable { * @return The model. */ public static ActivityChooserModel get(Context context, String historyFileName) { - if (historyFileName == null) { - return new ActivityChooserModel(context, historyFileName); - } synchronized (sRegistryLock) { ActivityChooserModel dataModel = sDataModelRegistry.get(historyFileName); if (dataModel == null) { @@ -380,7 +377,7 @@ public class ActivityChooserModel extends DataSetObservable { */ public int getActivityCount() { synchronized (mInstanceLock) { - return mActivitys.size(); + return mActivites.size(); } } @@ -389,12 +386,12 @@ public class ActivityChooserModel extends DataSetObservable { * * @return The activity. * - * @see Activity + * @see ActivityResolveInfo * @see #setIntent(Intent) */ public ResolveInfo getActivity(int index) { synchronized (mInstanceLock) { - return mActivitys.get(index).resolveInfo; + return mActivites.get(index).resolveInfo; } } @@ -406,10 +403,10 @@ public class ActivityChooserModel extends DataSetObservable { * @return The index if found, -1 otherwise. */ public int getActivityIndex(ResolveInfo activity) { - List<Activity> activities = mActivitys; + List<ActivityResolveInfo> activities = mActivites; final int activityCount = activities.size(); for (int i = 0; i < activityCount; i++) { - Activity currentActivity = activities.get(i); + ActivityResolveInfo currentActivity = activities.get(i); if (currentActivity.resolveInfo == activity) { return i; } @@ -433,8 +430,8 @@ public class ActivityChooserModel extends DataSetObservable { * @see HistoricalRecord */ public Intent chooseActivity(int index) { - Activity chosenActivity = mActivitys.get(index); - Activity defaultActivity = mActivitys.get(0); + ActivityResolveInfo chosenActivity = mActivites.get(index); + ActivityResolveInfo defaultActivity = mActivites.get(0); ComponentName chosenName = new ComponentName( chosenActivity.resolveInfo.activityInfo.packageName, @@ -460,8 +457,8 @@ public class ActivityChooserModel extends DataSetObservable { */ public ResolveInfo getDefaultActivity() { synchronized (mInstanceLock) { - if (!mActivitys.isEmpty()) { - return mActivitys.get(0).resolveInfo; + if (!mActivites.isEmpty()) { + return mActivites.get(0).resolveInfo; } } return null; @@ -478,8 +475,8 @@ public class ActivityChooserModel extends DataSetObservable { * @param index The index of the activity to set as default. */ public void setDefaultActivity(int index) { - Activity newDefaultActivity = mActivitys.get(index); - Activity oldDefaultActivity = mActivitys.get(0); + ActivityResolveInfo newDefaultActivity = mActivites.get(index); + ActivityResolveInfo oldDefaultActivity = mActivites.get(0); final float weight; if (oldDefaultActivity != null) { @@ -572,8 +569,8 @@ public class ActivityChooserModel extends DataSetObservable { */ private void sortActivities() { synchronized (mInstanceLock) { - if (mActivitySorter != null && !mActivitys.isEmpty()) { - mActivitySorter.sort(mIntent, mActivitys, + if (mActivitySorter != null && !mActivites.isEmpty()) { + mActivitySorter.sort(mIntent, mActivites, Collections.unmodifiableList(mHistoricalRecords)); notifyChanged(); } @@ -661,14 +658,14 @@ public class ActivityChooserModel extends DataSetObservable { * Loads the activities. */ private void loadActivitiesLocked() { - mActivitys.clear(); + mActivites.clear(); if (mIntent != null) { List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentActivities(mIntent, 0); final int resolveInfoCount = resolveInfos.size(); for (int i = 0; i < resolveInfoCount; i++) { ResolveInfo resolveInfo = resolveInfos.get(i); - mActivitys.add(new Activity(resolveInfo)); + mActivites.add(new ActivityResolveInfo(resolveInfo)); } sortActivities(); } else { @@ -797,7 +794,7 @@ public class ActivityChooserModel extends DataSetObservable { /** * Represents an activity. */ - public final class Activity implements Comparable<Activity> { + public final class ActivityResolveInfo implements Comparable<ActivityResolveInfo> { /** * The {@link ResolveInfo} of the activity. @@ -814,7 +811,7 @@ public class ActivityChooserModel extends DataSetObservable { * * @param resolveInfo activity {@link ResolveInfo}. */ - public Activity(ResolveInfo resolveInfo) { + public ActivityResolveInfo(ResolveInfo resolveInfo) { this.resolveInfo = resolveInfo; } @@ -834,14 +831,14 @@ public class ActivityChooserModel extends DataSetObservable { if (getClass() != obj.getClass()) { return false; } - Activity other = (Activity) obj; + ActivityResolveInfo other = (ActivityResolveInfo) obj; if (Float.floatToIntBits(weight) != Float.floatToIntBits(other.weight)) { return false; } return true; } - public int compareTo(Activity another) { + public int compareTo(ActivityResolveInfo another) { return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight); } @@ -862,18 +859,18 @@ public class ActivityChooserModel extends DataSetObservable { private final class DefaultSorter implements ActivitySorter { private static final float WEIGHT_DECAY_COEFFICIENT = 0.95f; - private final Map<String, Activity> mPackageNameToActivityMap = - new HashMap<String, Activity>(); + private final Map<String, ActivityResolveInfo> mPackageNameToActivityMap = + new HashMap<String, ActivityResolveInfo>(); - public void sort(Intent intent, List<Activity> activities, + public void sort(Intent intent, List<ActivityResolveInfo> activities, List<HistoricalRecord> historicalRecords) { - Map<String, Activity> packageNameToActivityMap = + Map<String, ActivityResolveInfo> packageNameToActivityMap = mPackageNameToActivityMap; packageNameToActivityMap.clear(); final int activityCount = activities.size(); for (int i = 0; i < activityCount; i++) { - Activity activity = activities.get(i); + ActivityResolveInfo activity = activities.get(i); activity.weight = 0.0f; String packageName = activity.resolveInfo.activityInfo.packageName; packageNameToActivityMap.put(packageName, activity); @@ -884,9 +881,11 @@ public class ActivityChooserModel extends DataSetObservable { for (int i = lastShareIndex; i >= 0; i--) { HistoricalRecord historicalRecord = historicalRecords.get(i); String packageName = historicalRecord.activity.getPackageName(); - Activity activity = packageNameToActivityMap.get(packageName); - activity.weight += historicalRecord.weight * nextRecordWeight; - nextRecordWeight = nextRecordWeight * WEIGHT_DECAY_COEFFICIENT; + ActivityResolveInfo activity = packageNameToActivityMap.get(packageName); + if (activity != null) { + activity.weight += historicalRecord.weight * nextRecordWeight; + nextRecordWeight = nextRecordWeight * WEIGHT_DECAY_COEFFICIENT; + } } Collections.sort(activities); diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java index 2fe8162..f500b39 100644 --- a/core/java/android/widget/ActivityChooserView.java +++ b/core/java/android/widget/ActivityChooserView.java @@ -16,10 +16,7 @@ package android.widget; -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -27,12 +24,20 @@ import android.content.res.TypedArray; import android.database.DataSetObserver; import android.graphics.Canvas; import android.graphics.drawable.Drawable; -import android.os.Debug; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ActivityChooserModel; import android.widget.ActivityChooserModel.ActivityChooserModelClient; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListPopupWindow; +import android.widget.PopupWindow; +import android.widget.TextView; import com.android.internal.R; @@ -56,11 +61,6 @@ import com.android.internal.R; * </li> * </ul> * </p> - * </p> - * This view is backed by a {@link ActivityChooserModel}. Calling {@link #showPopup()} - * while this view is attached to the view hierarchy will show a popup with - * activities while if the view is not attached it will show a dialog. - * </p> * * @hide */ @@ -92,29 +92,21 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod private final ImageButton mDefaultActionButton; /** - * The header for handlers list. + * Observer for the model data. */ - private final View mListHeaderView; + private final DataSetObserver mModelDataSetOberver = new DataSetObserver() { - /** - * The footer for handlers list. - */ - private final View mListFooterView; - - /** - * The title of the header view. - */ - private TextView mListHeaderViewTitle; - - /** - * The title for expanding the activities list. - */ - private final String mListHeaderViewTitleSelectDefault; - - /** - * The title if no activity exist. - */ - private final String mListHeaderViewTitleNoActivities; + @Override + public void onChanged() { + super.onChanged(); + mAdapter.notifyDataSetChanged(); + } + @Override + public void onInvalidated() { + super.onInvalidated(); + mAdapter.notifyDataSetInvalidated(); + } + }; /** * Popup window for showing the activity overflow list. @@ -122,11 +114,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod private ListPopupWindow mListPopupWindow; /** - * Alert dialog for showing the activity overflow list. - */ - private AlertDialog mAlertDialog; - - /** * Listener for the dismissal of the popup/alert. */ private PopupWindow.OnDismissListener mOnDismissListener; @@ -147,16 +134,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod private boolean mIsAttachedToWindow; /** - * Flag whether this view is showing an alert dialog. - */ - private boolean mIsShowingAlertDialog; - - /** - * Flag whether this view is showing a popup window. - */ - private boolean mIsShowingPopuWindow; - - /** * Create a new instance. * * @param context The application environment. @@ -195,8 +172,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod Drawable expandActivityOverflowButtonDrawable = attributesArray.getDrawable( R.styleable.ActivityChooserView_expandActivityOverflowButtonDrawable); - LayoutInflater inflater = (LayoutInflater) context.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); + LayoutInflater inflater = LayoutInflater.from(mContext); inflater.inflate(R.layout.activity_chooser_view, this, true); mCallbacks = new Callbacks(); @@ -211,15 +187,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod mExpandActivityOverflowButton.setOnClickListener(mCallbacks); mExpandActivityOverflowButton.setBackgroundDrawable(expandActivityOverflowButtonDrawable); - mListHeaderView = inflater.inflate(R.layout.activity_chooser_list_header, null); - mListFooterView = inflater.inflate(R.layout.activity_chooser_list_footer, null); - - mListHeaderViewTitle = (TextView) mListHeaderView.findViewById(R.id.title); - mListHeaderViewTitleSelectDefault = context.getString( - R.string.activity_chooser_view_select_default); - mListHeaderViewTitleNoActivities = context.getString( - R.string.activity_chooser_view_no_activities); - mAdapter = new ActivityChooserViewAdapter(); mAdapter.registerDataSetObserver(new DataSetObserver() { @Override @@ -262,7 +229,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod * @return True if the popup was shown, false if already showing. */ public boolean showPopup() { - if (isShowingPopup()) { + if (isShowingPopup() || !mIsAttachedToWindow) { return false; } mIsSelectingDefaultActivity = false; @@ -276,38 +243,29 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod * @param maxActivityCount The max number of activities to display. */ private void showPopupUnchecked(int maxActivityCount) { - mAdapter.setMaxActivityCount(maxActivityCount); - if (mIsSelectingDefaultActivity) { - if (mAdapter.getActivityCount() > 0) { - mListHeaderViewTitle.setText(mListHeaderViewTitleSelectDefault); - } else { - mListHeaderViewTitle.setText(mListHeaderViewTitleNoActivities); - } - mAdapter.setHeaderView(mListHeaderView); - } else { - mAdapter.setHeaderView(null); + if (mAdapter.getDataModel() == null) { + throw new IllegalStateException("No data model. Did you call #setDataModel?"); } - if (mAdapter.getActivityCount() > maxActivityCount + 1) { - mAdapter.setFooterView(mListFooterView); + mAdapter.setMaxActivityCount(maxActivityCount); + + final int activityCount = mAdapter.getActivityCount(); + if (maxActivityCount != ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED + && activityCount > maxActivityCount + 1) { + mAdapter.setShowFooterView(true); } else { - mAdapter.setFooterView(null); + mAdapter.setShowFooterView(false); } - if (!mIsAttachedToWindow || mIsShowingAlertDialog) { - AlertDialog alertDialog = getAlertDilalog(); - if (!alertDialog.isShowing()) { - alertDialog.setCustomTitle(this); - alertDialog.show(); - mIsShowingAlertDialog = true; - } - } else { - ListPopupWindow popupWindow = getListPopupWindow(); - if (!popupWindow.isShowing()) { - popupWindow.setContentWidth(mAdapter.measureContentWidth()); - popupWindow.show(); - mIsShowingPopuWindow = true; + ListPopupWindow popupWindow = getListPopupWindow(); + if (!popupWindow.isShowing()) { + if (mIsSelectingDefaultActivity) { + mAdapter.setShowDefaultActivity(true); + } else { + mAdapter.setShowDefaultActivity(false); } + popupWindow.setContentWidth(mAdapter.measureContentWidth()); + popupWindow.show(); } } @@ -317,12 +275,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod * @return True if dismissed, false if already dismissed. */ public boolean dismissPopup() { - if (!isShowingPopup()) { - return false; - } - if (mIsShowingAlertDialog) { - getAlertDilalog().dismiss(); - } else if (mIsShowingPopuWindow) { + if (isShowingPopup()) { getListPopupWindow().dismiss(); } return true; @@ -334,12 +287,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod * @return True if the popup is shown. */ public boolean isShowingPopup() { - if (mIsShowingAlertDialog) { - return getAlertDilalog().isShowing(); - } else if (mIsShowingPopuWindow) { - return getListPopupWindow().isShowing(); - } - return false; + return getListPopupWindow().isShowing(); } @Override @@ -347,6 +295,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod super.onAttachedToWindow(); ActivityChooserModel dataModel = mAdapter.getDataModel(); if (dataModel != null) { + dataModel.registerObserver(mModelDataSetOberver); dataModel.readHistoricalData(); } mIsAttachedToWindow = true; @@ -357,6 +306,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod super.onDetachedFromWindow(); ActivityChooserModel dataModel = mAdapter.getDataModel(); if (dataModel != null) { + dataModel.unregisterObserver(mModelDataSetOberver); dataModel.persistHistoricalData(); } mIsAttachedToWindow = false; @@ -371,13 +321,11 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - mActivityChooserContent.layout(left, top, right, bottom); - if (mIsShowingPopuWindow) { - if (isShown()) { - showPopupUnchecked(mAdapter.getMaxActivityCount()); - } else { - dismissPopup(); - } + mActivityChooserContent.layout(0, 0, right - left, bottom - top); + if (getListPopupWindow().isShowing()) { + showPopupUnchecked(mAdapter.getMaxActivityCount()); + } else { + dismissPopup(); } } @@ -429,22 +377,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod } /** - * Gets the alert dialog which is lazily initialized. - * - * @return The popup. - */ - private AlertDialog getAlertDilalog() { - if (mAlertDialog == null) { - Builder builder = new Builder(getContext()); - builder.setAdapter(mAdapter, null); - mAlertDialog = builder.create(); - mAlertDialog.getListView().setOnItemClickListener(mCallbacks); - mAlertDialog.setOnDismissListener(mCallbacks); - } - return mAlertDialog; - } - - /** * Updates the buttons state. */ private void updateButtons() { @@ -469,24 +401,23 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod * Interface implementation to avoid publishing them in the APIs. */ private class Callbacks implements AdapterView.OnItemClickListener, - View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener, - DialogInterface.OnDismissListener { + View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener { // AdapterView#OnItemClickListener public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ActivityChooserViewAdapter adapter = (ActivityChooserViewAdapter) parent.getAdapter(); final int itemViewType = adapter.getItemViewType(position); switch (itemViewType) { - case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_HEADER: { - /* do nothing */ - } break; case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_FOOTER: { showPopupUnchecked(ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED); } break; case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_ACTIVITY: { dismissPopup(); if (mIsSelectingDefaultActivity) { - mAdapter.getDataModel().setDefaultActivity(position); + // The item at position zero is the default already. + if (position > 0) { + mAdapter.getDataModel().setDefaultActivity(position); + } } else { // The first item in the model is default action => adjust index Intent launchIntent = mAdapter.getDataModel().chooseActivity(position + 1); @@ -530,16 +461,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod // PopUpWindow.OnDismissListener#onDismiss public void onDismiss() { - mIsShowingPopuWindow = false; - notifyOnDismissListener(); - } - - // DialogInterface.OnDismissListener#onDismiss - @Override - public void onDismiss(DialogInterface dialog) { - mIsShowingAlertDialog = false; - AlertDialog alertDialog = (AlertDialog) dialog; - alertDialog.setCustomTitle(null); notifyOnDismissListener(); } @@ -559,59 +480,35 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod public static final int MAX_ACTIVITY_COUNT_DEFAULT = 4; - private static final int ITEM_VIEW_TYPE_HEADER = 0; + private static final int ITEM_VIEW_TYPE_ACTIVITY = 0; - private static final int ITEM_VIEW_TYPE_ACTIVITY = 1; - - private static final int ITEM_VIEW_TYPE_FOOTER = 2; + private static final int ITEM_VIEW_TYPE_FOOTER = 1; private static final int ITEM_VIEW_TYPE_COUNT = 3; - private final DataSetObserver mDataSetOberver = new DataSetObserver() { - - @Override - public void onChanged() { - super.onChanged(); - notifyDataSetChanged(); - } - @Override - public void onInvalidated() { - super.onInvalidated(); - notifyDataSetInvalidated(); - } - }; - private ActivityChooserModel mDataModel; private int mMaxActivityCount = MAX_ACTIVITY_COUNT_DEFAULT; - private ResolveInfo mDefaultActivity; + private boolean mShowDefaultActivity; - private View mHeaderView; - - private View mFooterView; + private boolean mShowFooterView; public void setDataModel(ActivityChooserModel dataModel) { + ActivityChooserModel oldDataModel = mAdapter.getDataModel(); + if (oldDataModel != null && isShown()) { + oldDataModel.unregisterObserver(mModelDataSetOberver); + } mDataModel = dataModel; - mDataModel.registerObserver(mDataSetOberver); - notifyDataSetChanged(); - } - - @Override - public void notifyDataSetChanged() { - if (mDataModel.getActivityCount() > 0) { - mDefaultActivity = mDataModel.getDefaultActivity(); - } else { - mDefaultActivity = null; + if (dataModel != null && isShown()) { + dataModel.registerObserver(mModelDataSetOberver); } - super.notifyDataSetChanged(); + notifyDataSetChanged(); } @Override public int getItemViewType(int position) { - if (mHeaderView != null && position == 0) { - return ITEM_VIEW_TYPE_HEADER; - } else if (mFooterView != null && position == getCount() - 1) { + if (mShowFooterView && position == getCount() - 1) { return ITEM_VIEW_TYPE_FOOTER; } else { return ITEM_VIEW_TYPE_ACTIVITY; @@ -626,14 +523,11 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod public int getCount() { int count = 0; int activityCount = mDataModel.getActivityCount(); - if (activityCount > 0) { + if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) { activityCount--; } count = Math.min(activityCount, mMaxActivityCount); - if (mHeaderView != null) { - count++; - } - if (mFooterView != null) { + if (mShowFooterView) { count++; } return count; @@ -642,16 +536,13 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod public Object getItem(int position) { final int itemViewType = getItemViewType(position); switch (itemViewType) { - case ITEM_VIEW_TYPE_HEADER: - return mHeaderView; case ITEM_VIEW_TYPE_FOOTER: - return mFooterView; + return null; case ITEM_VIEW_TYPE_ACTIVITY: - int targetIndex = (mHeaderView == null) ? position : position - 1; - if (mDefaultActivity != null) { - targetIndex++; + if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) { + position++; } - return mDataModel.getActivity(targetIndex); + return mDataModel.getActivity(position); default: throw new IllegalArgumentException(); } @@ -661,27 +552,19 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod return position; } - @Override - public boolean isEnabled(int position) { - final int itemViewType = getItemViewType(position); - switch (itemViewType) { - case ITEM_VIEW_TYPE_HEADER: - return false; - case ITEM_VIEW_TYPE_FOOTER: - case ITEM_VIEW_TYPE_ACTIVITY: - return true; - default: - throw new IllegalArgumentException(); - } - } - public View getView(int position, View convertView, ViewGroup parent) { final int itemViewType = getItemViewType(position); switch (itemViewType) { - case ITEM_VIEW_TYPE_HEADER: - return mHeaderView; case ITEM_VIEW_TYPE_FOOTER: - return mFooterView; + if (convertView == null || convertView.getId() != ITEM_VIEW_TYPE_FOOTER) { + convertView = LayoutInflater.from(getContext()).inflate( + R.layout.activity_chooser_view_list_item, parent, false); + convertView.setId(ITEM_VIEW_TYPE_FOOTER); + TextView titleView = (TextView) convertView.findViewById(R.id.title); + titleView.setText(mContext.getString( + R.string.activity_chooser_view_see_all)); + } + return convertView; case ITEM_VIEW_TYPE_ACTIVITY: if (convertView == null || convertView.getId() != R.id.list_item) { convertView = LayoutInflater.from(getContext()).inflate( @@ -695,6 +578,12 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod // Set the title. TextView titleView = (TextView) convertView.findViewById(R.id.title); titleView.setText(activity.loadLabel(packageManager)); + // Highlight the default. + if (mShowDefaultActivity && position == 0) { + convertView.setActivated(true); + } else { + convertView.setActivated(false); + } return convertView; default: throw new IllegalArgumentException(); @@ -702,7 +591,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod } public int measureContentWidth() { - // The user may have specified some of the target not to be show but we + // The user may have specified some of the target not to be shown but we // want to measure all of them since after expansion they should fit. final int oldMaxActivityCount = mMaxActivityCount; mMaxActivityCount = MAX_ACTIVITY_COUNT_UNLIMITED; @@ -733,19 +622,12 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod } public ResolveInfo getDefaultActivity() { - return mDefaultActivity; - } - - public void setHeaderView(View headerView) { - if (mHeaderView != headerView) { - mHeaderView = headerView; - notifyDataSetChanged(); - } + return mDataModel.getDefaultActivity(); } - public void setFooterView(View footerView) { - if (mFooterView != footerView) { - mFooterView = footerView; + public void setShowFooterView(boolean showFooterView) { + if (mShowFooterView != showFooterView) { + mShowFooterView = showFooterView; notifyDataSetChanged(); } } @@ -761,5 +643,12 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod public ActivityChooserModel getDataModel() { return mDataModel; } + + public void setShowDefaultActivity(boolean showDefaultActivity) { + if (mShowDefaultActivity != showDefaultActivity) { + mShowDefaultActivity = showDefaultActivity; + notifyDataSetChanged(); + } + } } } diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index 3b16994..1b713c3 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -375,6 +375,7 @@ public class CalendarView extends FrameLayout { com.android.internal.R.styleable.TextAppearance); mDateTextSize = dateTextAppearance.getDimensionPixelSize( R.styleable.TextAppearance_textSize, DEFAULT_DATE_TEXT_SIZE); + dateTextAppearance.recycle(); int weekDayTextAppearanceResId = attributesArray.getResourceId( R.styleable.CalendarView_weekDayTextAppearance, diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java index f48261d..2e0cc62 100644 --- a/core/java/android/widget/ShareActionProvider.java +++ b/core/java/android/widget/ShareActionProvider.java @@ -16,21 +16,25 @@ package android.widget; -import com.android.internal.R; - import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.util.TypedValue; import android.view.ActionProvider; +import android.view.Menu; import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; import android.view.SubMenu; import android.view.View; +import com.android.internal.R; + /** * This is a provider for a share action. It is responsible for creating views - * that enable data sharing and also to perform a default action for showing - * a share dialog. + * that enable data sharing and also to show a sub menu with sharing activities + * if the hosting item is placed on the overflow menu. * <p> * Here is how to use the action provider with custom backing file in a {@link MenuItem}: * </p> @@ -48,15 +52,13 @@ import android.view.View; * // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this * // line if using the default share history file is desired. * mShareActionProvider.setShareHistoryFileName("custom_share_history.xml"); - * // Get the action view and hold onto it to set the share intent. - * mActionView = menuItem.getActionView(); * . . . * } * * // Somewhere in the application. * public void doShare(Intent shareIntent) { * // When you want to share set the share intent. - * mShareActionProvider.setShareIntent(mActionView, shareIntent); + * mShareActionProvider.setShareIntent(shareIntent); * } * </pre> * </code> @@ -71,11 +73,34 @@ import android.view.View; public class ShareActionProvider extends ActionProvider { /** + * The default for the maximal number of activities shown in the sub-menu. + */ + private static final int DEFAULT_INITIAL_ACTIVITY_COUNT = 4; + + /** + * The the maximum number activities shown in the sub-menu. + */ + private int mMaxShownActivityCount = DEFAULT_INITIAL_ACTIVITY_COUNT; + + /** + * Listener for handling menu item clicks. + */ + private final ShareMenuItemOnMenuItemClickListener mOnMenuItemClickListener = + new ShareMenuItemOnMenuItemClickListener(); + + /** * The default name for storing share history. */ public static final String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml"; + /** + * Context for accessing resources. + */ private final Context mContext; + + /** + * The name of the file with share history data. + */ private String mShareHistoryFileName = DEFAULT_SHARE_HISTORY_FILE_NAME; /** @@ -93,24 +118,59 @@ public class ShareActionProvider extends ActionProvider { */ @Override public View onCreateActionView() { + // Create the view and set its data model. ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName); ActivityChooserView activityChooserView = new ActivityChooserView(mContext); activityChooserView.setActivityChooserModel(dataModel); + + // Lookup and set the expand action icon. TypedValue outTypedValue = new TypedValue(); mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true); Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId); activityChooserView.setExpandActivityOverflowButtonDrawable(drawable); + return activityChooserView; } + /** + * {@inheritDoc} + */ @Override public boolean hasSubMenu() { return true; } + /** + * {@inheritDoc} + */ @Override public void onPrepareSubMenu(SubMenu subMenu) { - // TODO Implement me + // Clear since the order of items may change. + subMenu.clear(); + + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName); + PackageManager packageManager = mContext.getPackageManager(); + + final int expandedActivityCount = dataModel.getActivityCount(); + final int collapsedActivityCount = Math.min(expandedActivityCount, mMaxShownActivityCount); + + // Populate the sub-menu with a sub set of the activities. + for (int i = 0; i < collapsedActivityCount; i++) { + ResolveInfo activity = dataModel.getActivity(i); + subMenu.add(0, i, i, activity.loadLabel(packageManager)) + .setIcon(activity.loadIcon(packageManager)) + .setOnMenuItemClickListener(mOnMenuItemClickListener); + } + + // Add a sub-menu for showing all activities as a list item. + SubMenu expandedSubMenu = subMenu.addSubMenu(Menu.NONE, collapsedActivityCount, + collapsedActivityCount, mContext.getString(R.string.activity_chooser_view_see_all)); + for (int i = 0; i < expandedActivityCount; i++) { + ResolveInfo activity = dataModel.getActivity(i); + expandedSubMenu.add(0, i, i, activity.loadLabel(packageManager)) + .setIcon(activity.loadIcon(packageManager)) + .setOnMenuItemClickListener(mOnMenuItemClickListener); + } } /** @@ -145,18 +205,29 @@ public class ShareActionProvider extends ActionProvider { * </code> * </p> * - * @param actionView An action view created by {@link #onCreateActionView()}. * @param shareIntent The share intent. * * @see Intent#ACTION_SEND * @see Intent#ACTION_SEND_MULTIPLE */ - public void setShareIntent(View actionView, Intent shareIntent) { - if (actionView instanceof ActivityChooserView) { - ActivityChooserView activityChooserView = (ActivityChooserView) actionView; - activityChooserView.getDataModel().setIntent(shareIntent); - } else { - throw new IllegalArgumentException("actionView not instance of ActivityChooserView"); + public void setShareIntent(Intent shareIntent) { + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, + mShareHistoryFileName); + dataModel.setIntent(shareIntent); + } + + /** + * Reusable listener for handling share item clicks. + */ + private class ShareMenuItemOnMenuItemClickListener implements OnMenuItemClickListener { + @Override + public boolean onMenuItemClick(MenuItem item) { + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, + mShareHistoryFileName); + final int itemId = item.getItemId(); + Intent launchIntent = dataModel.chooseActivity(itemId); + mContext.startActivity(launchIntent); + return true; } } } diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index 9c06d69..80f68ac 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -544,6 +544,17 @@ public class ActionMenuPresenter extends BaseMenuPresenter { } setCallback(mPopupPresenterCallback); + + boolean preserveIconSpacing = false; + final int count = subMenu.size(); + for (int i = 0; i < count; i++) { + MenuItem childItem = subMenu.getItem(i); + if (childItem.isVisible() && childItem.getIcon() != null) { + preserveIconSpacing = true; + break; + } + } + setForceShowIcon(preserveIconSpacing); } @Override diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java index 56128d4..d1b1dae 100644 --- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java @@ -179,8 +179,10 @@ public class IconMenuPresenter extends BaseMenuPresenter { @Override public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { mOpenSubMenuId = 0; - mOpenSubMenu.dismiss(); - mOpenSubMenu = null; + if (mOpenSubMenu != null) { + mOpenSubMenu.dismiss(); + mOpenSubMenu = null; + } } @Override diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java index 0c3c605..a1e16d4 100644 --- a/core/java/com/android/internal/view/menu/ListMenuItemView.java +++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java @@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; @@ -50,6 +51,8 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView private LayoutInflater mInflater; + private boolean mForceShowIcon; + public ListMenuItemView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs); @@ -99,6 +102,10 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView setEnabled(itemData.isEnabled()); } + public void setForceShowIcon(boolean forceShow) { + mPreserveIconSpacing = mForceShowIcon = forceShow; + } + public void setTitle(CharSequence title) { if (title != null) { mTitleView.setText(title); @@ -189,12 +196,12 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView } public void setIcon(Drawable icon) { - final boolean showIcon = mItemData.shouldShowIcon(); + final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon; if (!showIcon && !mPreserveIconSpacing) { return; } - if (mIconView == null && icon == null) { + if (mIconView == null && icon == null && !mPreserveIconSpacing) { return; } @@ -213,6 +220,19 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView } } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (mIconView != null && mPreserveIconSpacing) { + // Enforce minimum icon spacing + ViewGroup.LayoutParams lp = getLayoutParams(); + LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams(); + if (lp.height > 0 && iconLp.width <= 0) { + iconLp.width = lp.height; + } + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + private void insertIconView() { LayoutInflater inflater = getInflater(); mIconView = (ImageView) inflater.inflate(com.android.internal.R.layout.list_menu_item_icon, @@ -241,7 +261,7 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView } public boolean showsIcon() { - return false; + return mForceShowIcon; } private LayoutInflater getInflater() { diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index b0b49213..164d581 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -799,7 +799,7 @@ public class MenuBuilder implements Menu { if (itemImpl == null || !itemImpl.isEnabled()) { return false; } - + boolean invoked = itemImpl.invoke(); if (itemImpl.hasCollapsibleActionView()) { diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index 0a7313c..541d101 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -320,11 +320,6 @@ public final class MenuItemImpl implements MenuItem { } void setSubMenu(SubMenuBuilder subMenu) { - if ((mMenu != null) && (mMenu instanceof SubMenu)) { - throw new UnsupportedOperationException( - "Attempt to add a sub-menu to a sub-menu."); - } - mSubMenu = subMenu; subMenu.setHeaderTitle(getTitle()); diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index 4ecc828..6265618 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -19,15 +19,16 @@ package com.android.internal.view.menu; import android.content.Context; import android.content.res.Resources; import android.os.Parcelable; -import android.util.DisplayMetrics; import android.view.KeyEvent; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.AdapterView; import android.widget.BaseAdapter; +import android.widget.FrameLayout; import android.widget.ListAdapter; import android.widget.ListPopupWindow; import android.widget.PopupWindow; @@ -58,6 +59,10 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On private Callback mPresenterCallback; + boolean mForceShowIcon; + + private ViewGroup mMeasureParent; + public MenuPopupHelper(Context context, MenuBuilder menu) { this(context, menu, null, false); } @@ -86,6 +91,10 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On mAnchorView = anchor; } + public void setForceShowIcon(boolean forceShow) { + mForceShowIcon = forceShow; + } + public void show() { if (!tryShow()) { throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); @@ -170,7 +179,10 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On itemType = positionType; itemView = null; } - itemView = adapter.getView(i, itemView, null); + if (mMeasureParent == null) { + mMeasureParent = new FrameLayout(mContext); + } + itemView = adapter.getView(i, itemView, mMeasureParent); itemView.measure(widthMeasureSpec, heightMeasureSpec); width = Math.max(width, itemView.getMeasuredWidth()); } @@ -228,6 +240,18 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On if (subMenu.hasVisibleItems()) { MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false); subPopup.setCallback(mPresenterCallback); + + boolean preserveIconSpacing = false; + final int count = subMenu.size(); + for (int i = 0; i < count; i++) { + MenuItem childItem = subMenu.getItem(i); + if (childItem.isVisible() && childItem.getIcon() != null) { + preserveIconSpacing = true; + break; + } + } + subPopup.setForceShowIcon(preserveIconSpacing); + if (subPopup.tryShow()) { if (mPresenterCallback != null) { mPresenterCallback.onOpenSubMenu(subMenu); @@ -293,6 +317,9 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On } MenuView.ItemView itemView = (MenuView.ItemView) convertView; + if (mForceShowIcon) { + ((ListMenuItemView) convertView).setForceShowIcon(true); + } itemView.initialize(getItem(position), 0); return convertView; } diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java index 2871073..c446cfb 100644 --- a/core/java/com/android/server/NetworkManagementSocketTagger.java +++ b/core/java/com/android/server/NetworkManagementSocketTagger.java @@ -16,24 +16,37 @@ package com.android.server; +import android.os.SystemProperties; +import android.util.Log; + import dalvik.system.SocketTagger; + import java.io.FileDescriptor; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.math.BigInteger; import java.net.SocketException; import java.nio.charset.Charsets; +import libcore.io.IoUtils; + /** * Assigns tags to sockets for traffic stats. */ public final class NetworkManagementSocketTagger extends SocketTagger { + private static final String TAG = "NetworkManagementSocketTagger"; + private static final boolean LOGD = false; - private static final boolean LOGI = false; - private static final boolean ENABLE_TAGGING = false; + /** + * {@link SystemProperties} key that indicates if {@code qtaguid} bandwidth + * controls have been enabled. + */ + // TODO: remove when always enabled, or once socket tagging silently fails. + public static final String PROP_QTAGUID_ENABLED = "net.qtaguid_enabled"; private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() { - @Override protected SocketTags initialValue() { + @Override + protected SocketTags initialValue() { return new SocketTags(); } }; @@ -50,11 +63,12 @@ public final class NetworkManagementSocketTagger extends SocketTagger { threadSocketTags.get().statsUid = uid; } - @Override public void tag(FileDescriptor fd) throws SocketException { + @Override + public void tag(FileDescriptor fd) throws SocketException { final SocketTags options = threadSocketTags.get(); - if (LOGI) { - System.logI("tagSocket(" + fd.getInt$() + ") with statsTag=" - + options.statsTag + ", statsUid=" + options.statsUid); + if (LOGD) { + Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=" + options.statsTag + + ", statsUid=" + options.statsUid); } try { // TODO: skip tagging when options would be no-op @@ -82,9 +96,10 @@ public final class NetworkManagementSocketTagger extends SocketTagger { internalModuleCtrl(cmd); } - @Override public void untag(FileDescriptor fd) throws SocketException { - if (LOGI) { - System.logI("untagSocket(" + fd.getInt$() + ")"); + @Override + public void untag(FileDescriptor fd) throws SocketException { + if (LOGD) { + Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); } try { unTagSocketFd(fd); @@ -125,31 +140,22 @@ public final class NetworkManagementSocketTagger extends SocketTagger { * */ private void internalModuleCtrl(String cmd) throws IOException { - if (!ENABLE_TAGGING) return; + if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return; - final FileOutputStream procOut; - // TODO: Use something like - // android.os.SystemProperties.getInt("persist.bandwidth.enable", 0) - // to see if tagging should happen or not. + // TODO: migrate to native library for tagging commands + FileOutputStream procOut = null; try { procOut = new FileOutputStream("/proc/net/xt_qtaguid/ctrl"); - } catch (FileNotFoundException e) { - if (LOGI) { - System.logI("Can't talk to kernel module:" + e); - } - return; - } - try { procOut.write(cmd.getBytes(Charsets.US_ASCII)); } finally { - procOut.close(); + IoUtils.closeQuietly(procOut); } } /** * Convert {@link Integer} tag to {@code /proc/} format. Assumes unsigned * base-10 format like {@code 2147483647}. Currently strips signed bit to - * avoid using {@link java.math.BigInteger}. + * avoid using {@link BigInteger}. */ public static String tagToKernel(int tag) { // TODO: eventually write in hex, since that's what proc exports diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index a61217a..23c6da7 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -623,16 +623,9 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) } /* enable debugging; set suspend=y to pause during VM init */ -#ifdef HAVE_ANDROID_OS /* use android ADB transport */ opt.optionString = "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y"; -#else - /* use TCP socket; address=0 means start at port 8000 and probe up */ - LOGI("Using TCP socket for JDWP\n"); - opt.optionString = - "-agentlib:jdwp=transport=dt_socket,suspend=n,server=y,address=0"; -#endif mOptions.add(opt); char enableDPBuf[sizeof("-Xdeadlockpredict:") + PROPERTY_VALUE_MAX]; diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index d54981e..c22b071 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -44,7 +44,6 @@ enum Tcp_Udp { // Returns an ASCII decimal number read from the specified file, -1 on error. static jlong readNumber(char const* filename) { -#ifdef HAVE_ANDROID_OS char buf[80]; int fd = open(filename, O_RDONLY); if (fd < 0) { @@ -62,9 +61,6 @@ static jlong readNumber(char const* filename) { close(fd); buf[len] = '\0'; return atoll(buf); -#else // Simulator - return -1; -#endif } static const char* mobile_iface_list[] = { @@ -101,7 +97,6 @@ static jlong getAll(const char** iface_list, const char* what) { // Returns the sum of numbers from the specified path under /sys/class/net/*, // -1 if no such file exists. static jlong readTotal(char const* suffix) { -#ifdef HAVE_ANDROID_OS char filename[PATH_MAX] = "/sys/class/net/"; DIR *dir = opendir(filename); if (dir == NULL) { @@ -123,9 +118,6 @@ static jlong readTotal(char const* suffix) { closedir(dir); return total; -#else // Simulator - return -1; -#endif } // Mobile stats get accessed a lot more often than total stats. diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 2297834..a4432c3 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -278,7 +278,6 @@ jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz); jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz); -#ifdef HAVE_ANDROID_OS /* pulled out of bionic */ extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); @@ -414,7 +413,6 @@ static void dumpNativeHeap(FILE* fp) fprintf(fp, "END\n"); } -#endif /*HAVE_ANDROID_OS*/ /* * Dump the native heap, writing human-readable output to the specified @@ -449,13 +447,9 @@ static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz, return; } -#ifdef HAVE_ANDROID_OS LOGD("Native heap dump starting...\n"); dumpNativeHeap(fp); LOGD("Native heap dump complete.\n"); -#else - fprintf(fp, "Native heap dump not available on this platform\n"); -#endif fclose(fp); } diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp index 89dce89..8d65cbc 100644 --- a/core/jni/android_os_FileUtils.cpp +++ b/core/jni/android_os_FileUtils.cpp @@ -28,11 +28,8 @@ #include <sys/types.h> #include <fcntl.h> #include <signal.h> - -#if HAVE_ANDROID_OS #include <sys/ioctl.h> #include <linux/msdos_fs.h> -#endif namespace android { @@ -53,7 +50,6 @@ jint android_os_FileUtils_setPermissions(JNIEnv* env, jobject clazz, jstring file, jint mode, jint uid, jint gid) { - #if HAVE_ANDROID_OS const jchar* str = env->GetStringCritical(file, 0); String8 file8; if (str) { @@ -70,15 +66,11 @@ jint android_os_FileUtils_setPermissions(JNIEnv* env, jobject clazz, } } return chmod(file8.string(), mode) == 0 ? 0 : errno; - #else - return ENOSYS; - #endif } jint android_os_FileUtils_getPermissions(JNIEnv* env, jobject clazz, jstring file, jintArray outArray) { - #if HAVE_ANDROID_OS const jchar* str = env->GetStringCritical(file, 0); String8 file8; if (str) { @@ -107,9 +99,6 @@ jint android_os_FileUtils_getPermissions(JNIEnv* env, jobject clazz, } env->ReleasePrimitiveArrayCritical(outArray, array, 0); return 0; - #else - return ENOSYS; - #endif } jint android_os_FileUtils_setUMask(JNIEnv* env, jobject clazz, jint mask) @@ -119,7 +108,6 @@ jint android_os_FileUtils_setUMask(JNIEnv* env, jobject clazz, jint mask) jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring path) { - #if HAVE_ANDROID_OS if (path == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return -1; @@ -137,9 +125,6 @@ jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring pat env->ReleaseStringUTFChars(path, pathStr); return result; - #else - return -1; - #endif } jboolean android_os_FileUtils_getFileStatus(JNIEnv* env, jobject clazz, jstring path, jobject fileStatus) { diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp index 9ae4a63..dc16990 100644 --- a/core/jni/android_os_Power.cpp +++ b/core/jni/android_os_Power.cpp @@ -70,16 +70,11 @@ setScreenState(JNIEnv *env, jobject clazz, jboolean on) static void android_os_Power_shutdown(JNIEnv *env, jobject clazz) { -#ifdef HAVE_ANDROID_OS android_reboot(ANDROID_RB_POWEROFF, 0, 0); -#else - sync(); -#endif } static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason) { -#ifdef HAVE_ANDROID_OS if (reason == NULL) { android_reboot(ANDROID_RB_RESTART, 0, 0); } else { @@ -88,9 +83,6 @@ static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason) env->ReleaseStringUTFChars(reason, chars); // In case it fails. } jniThrowIOException(env, errno); -#else - sync(); -#endif } static JNINativeMethod method_table[] = { diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index 2b09442..8f84b81 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -1115,7 +1115,7 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, LOGV("... uuid = %s", uuid); dbus_message_ref(msg); // increment refcount because we pass to java - env->CallBooleanMethod(nat->me, method_onAgentAuthorize, + env->CallVoidMethod(nat->me, method_onAgentAuthorize, env->NewStringUTF(object_path), env->NewStringUTF(uuid), int(msg)); diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp index 0fbe0e7..2c7bb84 100644 --- a/core/jni/android_util_Log.cpp +++ b/core/jni/android_util_Log.cpp @@ -58,9 +58,6 @@ static int toLevel(const char* value) static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level) { -#ifndef HAVE_ANDROID_OS - return false; -#else /* HAVE_ANDROID_OS */ int len; char key[PROPERTY_KEY_MAX]; char buf[PROPERTY_VALUE_MAX]; @@ -93,7 +90,6 @@ static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring len = property_get(key, buf, ""); int logLevel = toLevel(buf); return (logLevel >= 0 && level >= logLevel) ? true : false; -#endif /* HAVE_ANDROID_OS */ } /* diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index d1ba2d1..47d343a 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -352,20 +352,12 @@ void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name) jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid) { - #if HAVE_ANDROID_OS return setuid(uid) == 0 ? 0 : errno; - #else - return ENOSYS; - #endif } jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid) { - #if HAVE_ANDROID_OS return setgid(uid) == 0 ? 0 : errno; - #else - return ENOSYS; - #endif } static int pid_compare(const void* v1, const void* v2) diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp index 86fd9cb..7e5dede 100644 --- a/core/jni/com_android_internal_os_ZygoteInit.cpp +++ b/core/jni/com_android_internal_os_ZygoteInit.cpp @@ -27,13 +27,11 @@ #include <JNIHelp.h> #include "android_runtime/AndroidRuntime.h" -#ifdef HAVE_ANDROID_OS #include <linux/capability.h> #include <linux/prctl.h> #include <sys/prctl.h> extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap); extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap); -#endif namespace android { @@ -168,7 +166,6 @@ static void com_android_internal_os_ZygoteInit_setCloseOnExec (JNIEnv *env, static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env, jobject clazz, jlong permitted, jlong effective) { -#ifdef HAVE_ANDROID_OS struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata; int err; @@ -190,15 +187,11 @@ static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env, jniThrowIOException(env, errno); return; } -#endif /* HAVE_ANDROID_OS */ } static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env, jobject clazz, jint pid) { -#ifndef HAVE_ANDROID_OS - return (jlong)0; -#else struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata; int err; @@ -217,7 +210,6 @@ static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env, } return (jlong) capdata.permitted; -#endif /* HAVE_ANDROID_OS */ } static jint com_android_internal_os_ZygoteInit_selectReadable ( diff --git a/core/res/res/layout/activity_chooser_list_footer.xml b/core/res/res/layout/activity_chooser_list_footer.xml deleted file mode 100644 index c05ba1a..0000000 --- a/core/res/res/layout/activity_chooser_list_footer.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/list_footer" - android:paddingLeft="16dip" - android:paddingRight="16dip" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center" - android:orientation="vertical"> - - <View - android:id="@+id/divider" - android:layout_width="match_parent" - android:layout_height="2dip" - android:background="@android:color/holo_blue_light" /> - - <TextView - android:id="@+id/title" - android:layout_width="wrap_content" - android:layout_height="48dip" - android:gravity="center" - android:textAppearance="?android:attr/textAppearanceLargePopupMenu" - android:duplicateParentState="true" - android:singleLine="true" - android:text="@string/activity_chooser_view_see_all" /> - -</LinearLayout> diff --git a/core/res/res/layout/activity_chooser_list_header.xml b/core/res/res/layout/activity_chooser_list_header.xml deleted file mode 100644 index 0fb256f..0000000 --- a/core/res/res/layout/activity_chooser_list_header.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/list_header" - android:paddingLeft="16dip" - android:paddingRight="16dip" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center" - android:orientation="vertical"> - - <TextView - android:id="@+id/title" - android:layout_width="wrap_content" - android:layout_height="?android:attr/dropdownListPreferredItemHeight" - android:gravity="center" - android:textAppearance="?android:attr/textAppearanceLargePopupMenu" - android:duplicateParentState="true" - android:singleLine="true" /> - - <View - android:id="@+id/divider" - android:layout_width="match_parent" - android:layout_height="2dip" - android:src="@drawable/divider_strong_holo" /> - -</LinearLayout> diff --git a/core/res/res/layout/activity_chooser_view.xml b/core/res/res/layout/activity_chooser_view.xml index ccf49fc..902b3c0 100644 --- a/core/res/res/layout/activity_chooser_view.xml +++ b/core/res/res/layout/activity_chooser_view.xml @@ -25,11 +25,11 @@ <ImageButton android:id="@+id/default_activity_button" android:layout_width="32dip" android:layout_height="32dip" - android:layout_marginLeft="16dip" /> + android:layout_marginRight="8dip" /> <ImageButton android:id="@+id/expand_activities_button" android:layout_width="32dip" android:layout_height="32dip" - android:layout_marginLeft="16dip" /> + android:layout_marginLeft="8dip" /> </LinearLayout> diff --git a/core/res/res/layout/activity_chooser_view_list_item.xml b/core/res/res/layout/activity_chooser_view_list_item.xml index 61b7e70..f90044e 100644 --- a/core/res/res/layout/activity_chooser_view_list_item.xml +++ b/core/res/res/layout/activity_chooser_view_list_item.xml @@ -18,26 +18,35 @@ android:id="@+id/list_item" android:layout_width="match_parent" android:layout_height="?android:attr/dropdownListPreferredItemHeight" - android:gravity="center_vertical" android:paddingLeft="16dip" - android:paddingRight="16dip"> - - <ImageView - android:id="@+id/icon" - android:layout_width="32dip" - android:layout_height="32dip" - android:layout_gravity="center_vertical" - android:layout_marginRight="8dip" - android:duplicateParentState="true" /> - - <TextView - android:id="@+id/title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceLargePopupMenu" - android:singleLine="true" - android:duplicateParentState="true" - android:ellipsize="marquee" - android:fadingEdge="horizontal" /> + android:paddingRight="16dip" + android:background="?android:attr/activatedBackgroundIndicator" + android:orientation="vertical" > + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:duplicateParentState="true" > + + <ImageView + android:id="@+id/icon" + android:layout_width="32dip" + android:layout_height="32dip" + android:layout_gravity="center_vertical" + android:layout_marginRight="8dip" + android:duplicateParentState="true" /> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:textAppearance="?android:attr/textAppearanceLargePopupMenu" + android:duplicateParentState="true" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" /> + + </LinearLayout> </LinearLayout> diff --git a/core/res/res/layout/list_menu_item_icon.xml b/core/res/res/layout/list_menu_item_icon.xml index 6ff14dd..a885211 100644 --- a/core/res/res/layout/list_menu_item_icon.xml +++ b/core/res/res/layout/list_menu_item_icon.xml @@ -19,6 +19,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:layout_marginRight="8dip" + android:layout_marginLeft="8dip" + android:layout_marginRight="-8dip" + android:scaleType="center" android:duplicateParentState="true" /> diff --git a/core/res/res/layout/popup_menu_item_layout.xml b/core/res/res/layout/popup_menu_item_layout.xml index fef017d..1a12c01 100644 --- a/core/res/res/layout/popup_menu_item_layout.xml +++ b/core/res/res/layout/popup_menu_item_layout.xml @@ -18,7 +18,6 @@ android:layout_width="match_parent" android:layout_height="?android:attr/dropdownListPreferredItemHeight" android:minWidth="196dip" - android:paddingLeft="16dip" android:paddingRight="16dip"> <!-- Icon will be inserted here. --> @@ -29,6 +28,7 @@ android:layout_weight="1" android:layout_height="wrap_content" android:layout_gravity="center_vertical" + android:layout_marginLeft="16dip" android:duplicateParentState="true"> <TextView diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index a5e5f70..0f6e5cf 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -133,4 +133,7 @@ <!-- Size of right margin on Unsecure unlock LockScreen --> <dimen name="keyguard_lockscreen_status_line_font_right_margin">45dip</dimen> + <!-- Minimum popup width for selecting an activity in ActivityChooserDialog/ActivityChooserView. --> + <dimen name="activity_chooser_popup_min_width">200dip</dimen> + </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 70c204e..d0e3f14 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3036,9 +3036,10 @@ <!-- Title for a button to expand the list of activities in ActivityChooserView [CHAR LIMIT=25] --> <string name="activity_chooser_view_see_all">See all...</string> - <!-- Title for a message that there are no activities in ActivityChooserView [CHAR LIMIT=25] --> - <string name="activity_chooser_view_no_activities">No activities</string> - <!-- Title for a message that prompts selection of a default share handler in ActivityChooserView [CHAR LIMIT=25] --> - <string name="activity_chooser_view_select_default">Select default</string> + <!-- Title default for a dialog showing possible activities in ActivityChooserView [CHAR LIMIT=25] --> + <string name="activity_chooser_view_dialog_title_default">Select activity</string> + + <!-- Title for a dialog showing possible activities for sharing in ShareActionProvider [CHAR LIMIT=25] --> + <string name="share_action_provider_share_with">Share with...</string> </resources> diff --git a/docs/html/guide/developing/tools/adb.jd b/docs/html/guide/developing/tools/adb.jd index a109dc8..78d12ef 100644 --- a/docs/html/guide/developing/tools/adb.jd +++ b/docs/html/guide/developing/tools/adb.jd @@ -503,7 +503,7 @@ application and send 500 pseudo-random events to it.</p> <ul> <li><code>V</code> — Verbose (lowest priority)</li> <li><code>D</code> — Debug</li> - <li><code>I</code> — Info</li> + <li><code>I</code> — Info (default priority)</li> <li><code>W</code> — Warning</li> <li><code>E</code> — Error</li> <li><code>F</code> — Fatal</li> @@ -520,7 +520,7 @@ of each message, given as <code><priority>/<tag></code>. </p> <p>To reduce the log output to a manageable level, you can restrict log output using <em>filter expressions</em>. Filter expressions let you indicate to the system the tags-priority combinations that you are interested in — the system suppresses other messages for the specified tags. </p> -<p>A filter expression follows this format <code>tag:priority ...</code>, where <code>tag</code> indicates the tag of interest and <code>priority</code> indicates the <em>minimum</em> level of priority to report for that tag. Messages for that tag at or above the specified priority are written to the log. You can supply any number of <code>tag:priority</code> specifications in a single filter expression. The series of specifications is whitespace-delimited. </p> +<p>A filter expression follows this format <code>tag:priority ...</code>, where <code>tag</code> indicates the tag of interest and <code>priority</code> indicates the <em>minimum</em> level of priority to report for that tag. Messages for that tag at or above the specified priority are written to the log. You can supply any number of <code>tag:priority</code> specifications in a single filter expression. The series of specifications is whitespace-delimited. The default output is to show all log messages with the Info priority (*:I).</p> <p>Here's an example of a filter expression that suppresses all log messages except those with the tag "ActivityManager", at priority "Info" or above, and all log messages with tag "MyApp", with priority "Debug" or above:</p> diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index 3ec174e..f7dbe30 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -256,8 +256,7 @@ <li class="toggle-list"> <div><a href="<?cs var:toroot ?>guide/topics/renderscript/index.html"> <span class="en">RenderScript</span> - </a> - <span class="new">new!</span></div> + </a></div> <ul> <li><a href="<?cs var:toroot ?>guide/topics/renderscript/graphics.html"> <span class="en">3D Graphics</span> @@ -304,11 +303,9 @@ <!--<li><a style="color:gray;">Localization</a></li> --> <li><a href="<?cs var:toroot ?>guide/topics/appwidgets/index.html"> <span class="en">App Widgets</span></a> - <span class="new">updated</span> </li> <li><a href="<?cs var:toroot?>guide/topics/wireless/bluetooth.html"> <span class="en">Bluetooth</span></a> - <span class="new">updated</span> </li> <li><a href="<?cs var:toroot?>guide/topics/nfc/index.html"> <span class="en">Near Field Communication</span> @@ -316,7 +313,6 @@ <li class="toggle-list"> <div><a href="<?cs var:toroot?>guide/topics/usb/index.html"> <span class="en">USB</span></a> - <span class="new">new!</span> </div> <ul> <li><a href="<?cs var:toroot ?>guide/topics/usb/accessory.html">Accessory</a></li> @@ -341,7 +337,6 @@ </li> <li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html"> <span class="en">Device Administration</span></a> - <span class="new">updated</span> </li> <li class="toggle-list"> <div> diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd index 3fcfa89..362ee16 100644 --- a/docs/html/resources/dashboard/opengl.jd +++ b/docs/html/resources/dashboard/opengl.jd @@ -74,6 +74,6 @@ src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl= </tr> </table> -<p><em>Data collected during a 7-day period ending on May 6, 2011</em></p> +<p><em>Data collected during a 7-day period ending on July 1, 2011</em></p> </div> diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd index e980ca5..97df84f 100644 --- a/docs/html/sdk/ndk/index.jd +++ b/docs/html/sdk/ndk/index.jd @@ -1,16 +1,16 @@ ndk=true -ndk.win_download=android-ndk-r5c-windows.zip -ndk.win_bytes=61627716 -ndk.win_checksum=2c7423842fa0f46871eab118495d4b45 +ndk.win_download=android-ndk-r6-windows.zip +ndk.win_bytes=67642809 +ndk.win_checksum=9c7d5ccc02151a3e5e950c70dc05ac6d -ndk.mac_download=android-ndk-r5c-darwin-x86.tar.bz2 -ndk.mac_bytes=50714712 -ndk.mac_checksum=183bfbbd85cf8e4c0bd7531e8803e75d +ndk.mac_download=android-ndk-r6-darwin-x86.tar.bz2 +ndk.mac_bytes=52682746 +ndk.mac_checksum=a154905e49a6246abd823b75b6eda738 -ndk.linux_download=android-ndk-r5c-linux-x86.tar.bz2 -ndk.linux_bytes=44539890 -ndk.linux_checksum=7659dfdc97026ed1d913e224d0531f61 +ndk.linux_download=android-ndk-r6-linux-x86.tar.bz2 +ndk.linux_bytes=46425290 +ndk.linux_checksum=ff0a43085fe206696d5cdcef3f4f4637 page.title=Android NDK @jd:body @@ -62,6 +62,58 @@ padding: .25em 1em; <div class="toggleable open"> <a href="#" onclick="return toggleDiv(this)"><img src= "{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px"> + Android NDK, Revision 6</a> <em>(July 2011)</em> + + <div class="toggleme"> + <p>This release of the NDK includes support for the x86 ABI and other minor changes. + For detailed information describing the changes in this release, read the + <code>CHANGES.HTML</code> document included in the NDK package. + </p> + <dl> + <dt>General notes:</dt> + <dd> + <ul> + <li>Adds support for the x86 ABI, which allows you to generate machine code + that runs on compatible x86-based Android devices. Major features for x86 + include x86-specific toolchains, system headers, libraries and + debugging support. For all of the details regarding x86 support, + see <code>docs/CPU-X86.html</code> in the NDK package. + + <p>By default, code is generated for ARM-based devices, but you can add x86 to your + <code>APP_ABI</code> definition in your <code>Application.mk</code> file to build + for x86 platforms. For example, the following line instructs <code>ndk-build</code> + to build your code for three distinct ABIs:</p> + + <pre>APP_ABI := armeabi armeabi-v7a x86</pre> + + <p>Unless you rely on ARM-based assembly sources, you shouldn't need to touch + your <code>Android.mk</code> files to build x86 machine code.</p> + + </li> + + <li>You can build a standalone x86 toolchain using the <code>--toolchain=x86-4.4.3</code> + option when calling <code>make-standalone-toolchain.sh</code>. See + <code>docs/STANDALONE-TOOLCHAIN.html</code> for more details. + </li> + <li>The new <code>ndk-stack</code> tool lets you translate stack traces in + <code>logcat</code> that are generated by native code. The tool translates + instruction addresses into a readable format that contains things such + as the function, source file, and line number corresponding to each stack frame. + For more information and a usage example, see <code>docs/NDK-STACK.html</code>. + </li> + </ul> + </dd> + <dt>Other changes:</dt> + <dd><code>arm-eabi-4.4.0</code>, which had been deprecated since NDK r5, has been + removed from the NDK distribution.</dd> + + </dl> + </div> + </div> + +<div class="toggleable closed"> + <a href="#" onclick="return toggleDiv(this)"><img src= + "{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px"> Android NDK, Revision 5c</a> <em>(June 2011)</em> <div class="toggleme"> diff --git a/docs/html/sdk/ndk/overview.jd b/docs/html/sdk/ndk/overview.jd index 2562a25..93c664d 100644 --- a/docs/html/sdk/ndk/overview.jd +++ b/docs/html/sdk/ndk/overview.jd @@ -53,11 +53,7 @@ page.title=What is the NDK? <li>ARMv7-A (including Thumb-2 and VFPv3-D16 instructions, with optional support for NEON/VFPv3-D32 instructions)</li> - </ul> - - <p>Future releases of the NDK will also support:</p> - <ul> <li>x86 instructions (see CPU-ARCH-ABIS.HTML for more information)</li> </ul> diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index 0607aad..0539adb 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -77,7 +77,7 @@ class="new">new!</span></li> <ul> <li class="toggle-list"> <div><a href="<?cs var:toroot ?>sdk/android-3.1.html"> - <span class="en">Android 3.1 Platform</span></a> <span class="new">new!</span></div> + <span class="en">Android 3.1 Platform</span></a></div> <ul> <li><a href="<?cs var:toroot ?>sdk/android-3.1-highlights.html">Platform Highlights</a></li> <li><a href="<?cs var:toroot ?>sdk/api_diff/12/changes.html">API Differences Report »</a></li> @@ -91,7 +91,7 @@ class="new">new!</span></li> <li><a href="<?cs var:toroot ?>sdk/api_diff/11/changes.html">API Differences Report »</a></li> </ul> </li> - <li><a href="<?cs var:toroot ?>sdk/android-2.3.4.html">Android 2.3.4 Platform</span></a> <span class="new">new!</span></li> + <li><a href="<?cs var:toroot ?>sdk/android-2.3.4.html">Android 2.3.4 Platform</span></a></li> <li class="toggle-list"> <div><a href="<?cs var:toroot ?>sdk/android-2.3.3.html"> <span class="en">Android 2.3.3 Platform</span></a></div> @@ -137,8 +137,8 @@ class="new">new!</span></li> <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r12</a> <span class="new">new!</span></li> <li><a href="<?cs var:toroot ?>sdk/win-usb.html">Google USB Driver, r4</a></li> - <li><a href="<?cs var:toroot ?>sdk/compatibility-library.html">Compatibility Library, r2</a> <span -class="new">new!</span></li> + <li><a href="<?cs var:toroot ?>sdk/compatibility-library.html">Compatibility Library, +r2</a></li> </ul> </li> <li> @@ -175,7 +175,7 @@ class="new">new!</span></li> <span style="display:none" class="zh-TW"></span> </h2> <ul> - <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r5c <span + <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r6 <span class="new">new!</span></a> </li> <li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li> diff --git a/include/media/stagefright/ShoutcastSource.h b/include/media/stagefright/ShoutcastSource.h deleted file mode 100644 index bc67156..0000000 --- a/include/media/stagefright/ShoutcastSource.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SHOUTCAST_SOURCE_H_ - -#define SHOUTCAST_SOURCE_H_ - -#include <sys/types.h> - -#include <media/stagefright/MediaSource.h> - -namespace android { - -class HTTPStream; -class MediaBufferGroup; - -class ShoutcastSource : public MediaSource { -public: - // Assumes ownership of "http". - ShoutcastSource(HTTPStream *http); - - virtual status_t start(MetaData *params = NULL); - virtual status_t stop(); - - virtual sp<MetaData> getFormat(); - - virtual status_t read( - MediaBuffer **buffer, const ReadOptions *options = NULL); - -protected: - virtual ~ShoutcastSource(); - -private: - HTTPStream *mHttp; - size_t mMetaDataOffset; - size_t mBytesUntilMetaData; - - MediaBufferGroup *mGroup; - bool mStarted; - - ShoutcastSource(const ShoutcastSource &); - ShoutcastSource &operator= (const ShoutcastSource &); -}; - -} // namespace android - -#endif // SHOUTCAST_SOURCE_H_ - diff --git a/include/private/binder/binder_module.h b/include/private/binder/binder_module.h index fdf327e..a8dd64f 100644 --- a/include/private/binder/binder_module.h +++ b/include/private/binder/binder_module.h @@ -21,126 +21,11 @@ namespace android { #endif -#if defined(HAVE_ANDROID_OS) - /* obtain structures and constants from the kernel header */ #include <sys/ioctl.h> #include <linux/binder.h> -#else - -/* Some parts of the simulator need fake versions of this - * stuff in order to compile. Really this should go away - * entirely... - */ - -#define BINDER_CURRENT_PROTOCOL_VERSION 7 - -#define BINDER_TYPE_BINDER 1 -#define BINDER_TYPE_WEAK_BINDER 2 -#define BINDER_TYPE_HANDLE 3 -#define BINDER_TYPE_WEAK_HANDLE 4 -#define BINDER_TYPE_FD 5 - -struct flat_binder_object { - unsigned long type; - unsigned long flags; - union { - void *binder; - signed long handle; - }; - void *cookie; -}; - -struct binder_write_read { - signed long write_size; - signed long write_consumed; - unsigned long write_buffer; - signed long read_size; - signed long read_consumed; - unsigned long read_buffer; -}; - -struct binder_transaction_data { - union { - size_t handle; - void *ptr; - } target; - void *cookie; - unsigned int code; - - unsigned int flags; - pid_t sender_pid; - uid_t sender_euid; - size_t data_size; - size_t offsets_size; - - union { - struct { - const void *buffer; - const void *offsets; - } ptr; - uint8_t buf[8]; - } data; -}; - -enum transaction_flags { - TF_ONE_WAY = 0x01, - TF_ROOT_OBJECT = 0x04, - TF_STATUS_CODE = 0x08, - TF_ACCEPT_FDS = 0x10, -}; - - -enum { - FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, - FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, -}; - -enum BinderDriverReturnProtocol { - BR_ERROR, - BR_OK, - BR_TRANSACTION, - BR_REPLY, - BR_ACQUIRE_RESULT, - BR_DEAD_REPLY, - BR_TRANSACTION_COMPLETE, - BR_INCREFS, - BR_ACQUIRE, - BR_RELEASE, - BR_DECREFS, - BR_ATTEMPT_ACQUIRE, - BR_NOOP, - BR_SPAWN_LOOPER, - BR_FINISHED, - BR_DEAD_BINDER, - BR_CLEAR_DEATH_NOTIFICATION_DONE, - BR_FAILED_REPLY, -}; - -enum BinderDriverCommandProtocol { - BC_TRANSACTION, - BC_REPLY, - BC_ACQUIRE_RESULT, - BC_FREE_BUFFER, - BC_INCREFS, - BC_ACQUIRE, - BC_RELEASE, - BC_DECREFS, - BC_INCREFS_DONE, - BC_ACQUIRE_DONE, - BC_ATTEMPT_ACQUIRE, - BC_REGISTER_LOOPER, - BC_ENTER_LOOPER, - BC_EXIT_LOOPER, - BC_REQUEST_DEATH_NOTIFICATION, - BC_CLEAR_DEATH_NOTIFICATION, - BC_DEAD_BINDER_DONE, -}; - -#endif - #ifdef __cplusplus } // namespace android #endif diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 7264ac4..f5288c8 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -154,11 +154,7 @@ bool ProcessState::becomeContextManager(context_check_func checkFunc, void* user mBinderContextUserData = userData; int dummy = 0; -#if defined(HAVE_ANDROID_OS) status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy); -#else - status_t result = INVALID_OPERATION; -#endif if (result == 0) { mManagesContexts = true; } else if (result == -1) { @@ -304,12 +300,7 @@ static int open_driver() if (fd >= 0) { fcntl(fd, F_SETFD, FD_CLOEXEC); int vers; -#if defined(HAVE_ANDROID_OS) status_t result = ioctl(fd, BINDER_VERSION, &vers); -#else - status_t result = -1; - errno = EPERM; -#endif if (result == -1) { LOGE("Binder ioctl to obtain version failed: %s", strerror(errno)); close(fd); @@ -320,14 +311,11 @@ static int open_driver() close(fd); fd = -1; } -#if defined(HAVE_ANDROID_OS) size_t maxThreads = 15; result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); if (result == -1) { LOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); } -#endif - } else { LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno)); } diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 563d7e4..e232ddd 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -73,7 +73,6 @@ void Caches::dumpMemoryUsage() { String8 stringLog; dumpMemoryUsage(stringLog); LOGD("%s", stringLog.string()); - delete stringLog; } void Caches::dumpMemoryUsage(String8 &log) { diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 7c10518..47049e2 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -43,7 +43,7 @@ enum DebugLevel { kDebugDisabled = 0, kDebugMemory = 1, kDebugCaches = 2, - kDebugMoreCaches = 3 + kDebugMoreCaches = kDebugMemory | kDebugCaches }; // These properties are defined in mega-bytes diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp index 62eb24e..bbf2836 100644 --- a/libs/rs/driver/rsdBcc.cpp +++ b/libs/rs/driver/rsdBcc.cpp @@ -269,6 +269,7 @@ static void wc_x(void *usr, uint32_t idx) { void rsdScriptInvokeForEach(const Context *rsc, Script *s, + uint32_t slot, const Allocation * ain, Allocation * aout, const void * usr, diff --git a/libs/rs/driver/rsdBcc.h b/libs/rs/driver/rsdBcc.h index 62b50f4..67929bc 100644 --- a/libs/rs/driver/rsdBcc.h +++ b/libs/rs/driver/rsdBcc.h @@ -32,6 +32,7 @@ void rsdScriptInvokeFunction(const android::renderscript::Context *dc, void rsdScriptInvokeForEach(const android::renderscript::Context *rsc, android::renderscript::Script *s, + uint32_t slot, const android::renderscript::Allocation * ain, android::renderscript::Allocation * aout, const void * usr, diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index 44e9d89..8798612 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -693,7 +693,9 @@ RsContext rsContextCreateGL(RsDevice vdev, uint32_t version, LOGV("rsContextCreateGL %p", vdev); Device * dev = static_cast<Device *>(vdev); Context *rsc = Context::createContext(dev, &sc); - rsc->setDPI(dpi); + if (rsc) { + rsc->setDPI(dpi); + } LOGV("rsContextCreateGL ret %p ", rsc); return rsc; } diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index b230bb5..e8b1014 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -121,7 +121,7 @@ void ScriptC::runForEach(Context *rsc, setupGLState(rsc); setupScript(rsc); - rsc->mHal.funcs.script.invokeForEach(rsc, this, ain, aout, usr, usrBytes, sc); + rsc->mHal.funcs.script.invokeForEach(rsc, this, 0, ain, aout, usr, usrBytes, sc); } void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) { diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h index 928dca5..6a4537b 100644 --- a/libs/rs/rs_hal.h +++ b/libs/rs/rs_hal.h @@ -70,6 +70,7 @@ typedef struct { int (*invokeRoot)(const Context *rsc, Script *s); void (*invokeForEach)(const Context *rsc, Script *s, + uint32_t slot, const Allocation * ain, Allocation * aout, const void * usr, diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index c46d6f4..1e602e9 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -83,7 +83,9 @@ status_t InputChannel::openInputChannelPair(const String8& name, sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) { status_t result; - int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE); + String8 ashmemName("InputChannel "); + ashmemName.append(name); + int serverAshmemFd = ashmem_create_region(ashmemName.string(), DEFAULT_MESSAGE_BUFFER_SIZE); if (serverAshmemFd < 0) { result = -errno; LOGE("channel '%s' ~ Could not create shared memory region. errno=%d", diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp index 87549fe..7ef30f9 100644 --- a/libs/utils/BackupHelpers.cpp +++ b/libs/utils/BackupHelpers.cpp @@ -481,6 +481,14 @@ static int write_pax_header_entry(char* buf, const char* key, const char* value) return sprintf(buf, "%d %s=%s\n", len, key, value); } +// Wire format to the backup manager service is chunked: each chunk is prefixed by +// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD. +void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) { + uint32_t chunk_size_no = htonl(size); + writer->WriteEntityData(&chunk_size_no, 4); + if (size != 0) writer->WriteEntityData(buffer, size); +} + int write_tarfile(const String8& packageName, const String8& domain, const String8& rootpath, const String8& filepath, BackupDataWriter* writer) { @@ -660,16 +668,16 @@ int write_tarfile(const String8& packageName, const String8& domain, // Checksum and write the pax block header calc_tar_checksum(paxHeader); - writer->WriteEntityData(paxHeader, 512); + send_tarfile_chunk(writer, paxHeader, 512); // Now write the pax data itself int paxblocks = (paxLen + 511) / 512; - writer->WriteEntityData(paxData, 512 * paxblocks); + send_tarfile_chunk(writer, paxData, 512 * paxblocks); } // Checksum and write the 512-byte ustar file header block to the output calc_tar_checksum(buf); - writer->WriteEntityData(buf, 512); + send_tarfile_chunk(writer, buf, 512); // Now write the file data itself, for real files. We honor tar's convention that // only full 512-byte blocks are sent to write(). @@ -699,7 +707,7 @@ int write_tarfile(const String8& packageName, const String8& domain, memset(buf + nRead, 0, remainder); nRead += remainder; } - writer->WriteEntityData(buf, nRead); + send_tarfile_chunk(writer, buf, nRead); toWrite -= nRead; } } diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index e8ddd2d..e89be08 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -835,6 +835,9 @@ public class MediaScanner } } + // For inserts we always use the file URI so we can insert in bulk. + // For updates we compute the URI based on the media type. + Uri tableUri = mFilesUri; Uri result = null; if (rowId == 0) { if (mMtpObjectHandle != 0) { @@ -850,7 +853,7 @@ public class MediaScanner if (mFileInserter != null) { result = mFileInserter.insert(values); } else { - result = mMediaProvider.insert(mFilesUri, values); + result = mMediaProvider.insert(tableUri, values); } if (result != null) { @@ -858,8 +861,18 @@ public class MediaScanner entry.mRowId = rowId; } } else { + if (!mNoMedia) { + if (MediaFile.isVideoFileType(mFileType)) { + tableUri = mVideoUri; + } else if (MediaFile.isImageFileType(mFileType)) { + tableUri = mImagesUri; + } else if (MediaFile.isAudioFileType(mFileType)) { + tableUri = mAudioUri; + } + } + // updated file - result = ContentUris.withAppendedId(mFilesUri, rowId); + result = ContentUris.withAppendedId(tableUri, rowId); // path should never change, and we want to avoid replacing mixed cased paths // with squashed lower case paths values.remove(MediaStore.MediaColumns.DATA); @@ -909,19 +922,19 @@ public class MediaScanner if (notifications && !mDefaultNotificationSet) { if (TextUtils.isEmpty(mDefaultNotificationFilename) || doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) { - setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, mFilesUri, rowId); + setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId); mDefaultNotificationSet = true; } } else if (ringtones && !mDefaultRingtoneSet) { if (TextUtils.isEmpty(mDefaultRingtoneFilename) || doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) { - setSettingIfNotSet(Settings.System.RINGTONE, mFilesUri, rowId); + setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId); mDefaultRingtoneSet = true; } } else if (alarms && !mDefaultAlarmSet) { if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) || doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) { - setSettingIfNotSet(Settings.System.ALARM_ALERT, mFilesUri, rowId); + setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId); mDefaultAlarmSet = true; } } diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index 0f3c063..4dbcb90 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -79,7 +79,6 @@ MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) { return (MtpDatabase *)env->GetIntField(database, field_context); } -#ifdef HAVE_ANDROID_OS // ---------------------------------------------------------------------------- class MyMtpDatabase : public MtpDatabase { @@ -1066,42 +1065,32 @@ void MyMtpDatabase::sessionEnded() { checkAndClearExceptionFromCallback(env, __FUNCTION__); } -#endif // HAVE_ANDROID_OS - // ---------------------------------------------------------------------------- static void android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz) { -#ifdef HAVE_ANDROID_OS MyMtpDatabase* database = new MyMtpDatabase(env, thiz); env->SetIntField(thiz, field_context, (int)database); checkAndClearExceptionFromCallback(env, __FUNCTION__); -#endif } static void android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz) { -#ifdef HAVE_ANDROID_OS MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context); database->cleanup(env); delete database; env->SetIntField(thiz, field_context, 0); checkAndClearExceptionFromCallback(env, __FUNCTION__); -#endif } static jstring android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject thiz, jlong seconds) { -#ifdef HAVE_ANDROID_OS char date[20]; formatDateTime(seconds, date, sizeof(date)); return env->NewStringUTF(date); -#else - return NULL; -#endif } // ---------------------------------------------------------------------------- diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp index 40bbaa3..6b73f6c 100644 --- a/media/jni/android_mtp_MtpDevice.cpp +++ b/media/jni/android_mtp_MtpDevice.cpp @@ -85,8 +85,6 @@ static jfieldID field_objectInfo_dateCreated; static jfieldID field_objectInfo_dateModified; static jfieldID field_objectInfo_keywords; -#ifdef HAVE_ANDROID_OS - MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice) { return (MtpDevice*)env->GetIntField(javaDevice, field_context); @@ -100,15 +98,11 @@ static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodNa } } -#endif // HAVE_ANDROID_OS - // ---------------------------------------------------------------------------- static jboolean android_mtp_MtpDevice_open(JNIEnv *env, jobject thiz, jstring deviceName, jint fd) { -#ifdef HAVE_ANDROID_OS - LOGD("open\n"); const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL); if (deviceNameStr == NULL) { return false; @@ -120,27 +114,22 @@ android_mtp_MtpDevice_open(JNIEnv *env, jobject thiz, jstring deviceName, jint f if (device) env->SetIntField(thiz, field_context, (int)device); return (device != NULL); -#endif } static void android_mtp_MtpDevice_close(JNIEnv *env, jobject thiz) { -#ifdef HAVE_ANDROID_OS - LOGD("close\n"); MtpDevice* device = get_device_from_object(env, thiz); if (device) { device->close(); delete device; env->SetIntField(thiz, field_context, 0); } -#endif } static jobject android_mtp_MtpDevice_get_device_info(JNIEnv *env, jobject thiz) { -#ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (!device) { LOGD("android_mtp_MtpDevice_get_device_info device is null"); @@ -173,15 +162,11 @@ android_mtp_MtpDevice_get_device_info(JNIEnv *env, jobject thiz) delete deviceInfo; return info; -#else - return NULL; -#endif } static jintArray android_mtp_MtpDevice_get_storage_ids(JNIEnv *env, jobject thiz) { -#ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; @@ -196,15 +181,11 @@ android_mtp_MtpDevice_get_storage_ids(JNIEnv *env, jobject thiz) delete storageIDs; return array; -#else - return NULL; -#endif } static jobject android_mtp_MtpDevice_get_storage_info(JNIEnv *env, jobject thiz, jint storageID) { -#ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; @@ -234,16 +215,12 @@ android_mtp_MtpDevice_get_storage_info(JNIEnv *env, jobject thiz, jint storageID delete storageInfo; return info; -#else - return NULL; -#endif } static jintArray android_mtp_MtpDevice_get_object_handles(JNIEnv *env, jobject thiz, jint storageID, jint format, jint objectID) { -#ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; @@ -258,15 +235,11 @@ android_mtp_MtpDevice_get_object_handles(JNIEnv *env, jobject thiz, delete handles; return array; -#else - return NULL; -#endif } static jobject android_mtp_MtpDevice_get_object_info(JNIEnv *env, jobject thiz, jint objectID) { -#ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; @@ -324,9 +297,6 @@ android_mtp_MtpDevice_get_object_info(JNIEnv *env, jobject thiz, jint objectID) delete objectInfo; return info; -#else - return NULL; -#endif } struct get_object_callback_data { @@ -344,7 +314,6 @@ static bool get_object_callback(void* data, int offset, int length, void* client static jbyteArray android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jint objectSize) { -#ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; @@ -361,14 +330,12 @@ android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jint if (device->readObject(objectID, get_object_callback, objectSize, &data)) return array; -#endif return NULL; } static jbyteArray android_mtp_MtpDevice_get_thumbnail(JNIEnv *env, jobject thiz, jint objectID) { -#ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; @@ -382,51 +349,41 @@ android_mtp_MtpDevice_get_thumbnail(JNIEnv *env, jobject thiz, jint objectID) free(thumbnail); return array; -#else - return NULL; -#endif } static jboolean android_mtp_MtpDevice_delete_object(JNIEnv *env, jobject thiz, jint object_id) { -#ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (device) return device->deleteObject(object_id); else - #endif return NULL; } static jlong android_mtp_MtpDevice_get_parent(JNIEnv *env, jobject thiz, jint object_id) { -#ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (device) return device->getParent(object_id); else -#endif return -1; } static jlong android_mtp_MtpDevice_get_storage_id(JNIEnv *env, jobject thiz, jint object_id) { - #ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (device) return device->getStorageID(object_id); else -#endif return -1; } static jboolean android_mtp_MtpDevice_import_file(JNIEnv *env, jobject thiz, jint object_id, jstring dest_path) { -#ifdef HAVE_ANDROID_OS MtpDevice* device = get_device_from_object(env, thiz); if (device) { const char *destPathStr = env->GetStringUTFChars(dest_path, NULL); @@ -438,7 +395,7 @@ android_mtp_MtpDevice_import_file(JNIEnv *env, jobject thiz, jint object_id, jst env->ReleaseStringUTFChars(dest_path, destPathStr); return result; } -#endif + return false; } diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 7b3b95b..e17e1e8 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -3,8 +3,6 @@ include $(CLEAR_VARS) include frameworks/base/media/libstagefright/codecs/common/Config.mk -BUILD_WITH_SOFTWARE_DECODERS := false - LOCAL_SRC_FILES:= \ ACodec.cpp \ AACExtractor.cpp \ @@ -24,7 +22,6 @@ LOCAL_SRC_FILES:= \ FileSource.cpp \ FLACExtractor.cpp \ HTTPBase.cpp \ - HTTPStream.cpp \ JPEGSource.cpp \ MP3Extractor.cpp \ MPEG2TSWriter.cpp \ @@ -38,13 +35,11 @@ LOCAL_SRC_FILES:= \ MediaSourceSplitter.cpp \ MetaData.cpp \ NuCachedSource2.cpp \ - NuHTTPDataSource.cpp \ OMXClient.cpp \ OMXCodec.cpp \ OggExtractor.cpp \ SampleIterator.cpp \ SampleTable.cpp \ - ShoutcastSource.cpp \ StagefrightMediaScanner.cpp \ StagefrightMetadataRetriever.cpp \ ThrottledSource.cpp \ @@ -96,26 +91,6 @@ LOCAL_STATIC_LIBRARIES := \ libstagefright_id3 \ libFLAC \ -ifeq ($(BUILD_WITH_SOFTWARE_DECODERS),true) - -LOCAL_SRC_FILES += \ - ThreadedSource.cpp \ - -LOCAL_STATIC_LIBRARIES += \ - libstagefright_aacdec \ - libstagefright_amrnbdec \ - libstagefright_amrwbdec \ - libstagefright_avcdec \ - libstagefright_g711dec \ - libstagefright_mp3dec \ - libstagefright_m4vh263dec \ - libstagefright_vorbisdec \ - libstagefright_vpxdec \ - libvpx \ - -endif - - ################################################################################ # The following was shamelessly copied from external/webkit/Android.mk and @@ -177,10 +152,6 @@ LOCAL_SHARED_LIBRARIES += \ LOCAL_CFLAGS += -Wno-multichar -ifeq ($(BUILD_WITH_SOFTWARE_DECODERS),true) - LOCAL_CFLAGS += -DHAVE_SOFTWARE_DECODERS -endif - LOCAL_MODULE:= libstagefright include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp index 0d24551..f9d8501 100644 --- a/media/libstagefright/HTTPBase.cpp +++ b/media/libstagefright/HTTPBase.cpp @@ -24,10 +24,11 @@ #include "include/ChromiumHTTPDataSource.h" #endif -#include "include/NuHTTPDataSource.h" - +#include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/ALooper.h> + #include <cutils/properties.h> +#include <cutils/qtaguid.h> namespace android { @@ -44,14 +45,12 @@ HTTPBase::HTTPBase() // static sp<HTTPBase> HTTPBase::Create(uint32_t flags) { #if CHROMIUM_AVAILABLE - char value[PROPERTY_VALUE_MAX]; - if (!property_get("media.stagefright.use-chromium", value, NULL) - || (strcasecmp("false", value) && strcmp("0", value))) { return new ChromiumHTTPDataSource(flags); - } else #endif { - return new NuHTTPDataSource(flags); + TRESPASS(); + + return NULL; } } @@ -135,4 +134,10 @@ bool HTTPBase::getUID(uid_t *uid) const { return true; } +// static +void HTTPBase::RegisterSocketUser(int s, uid_t uid) { + static const uint32_t kTag = 0xdeadbeef; + set_qtaguid(s, kTag, uid); +} + } // namespace android diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp deleted file mode 100644 index d526ebd..0000000 --- a/media/libstagefright/HTTPStream.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "HTTPStream" -#include <utils/Log.h> - -#include "include/HTTPStream.h" - -#include <sys/socket.h> - -#include <arpa/inet.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <netdb.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <media/stagefright/foundation/ADebug.h> - -#include <openssl/ssl.h> - -namespace android { - -// static -const char *HTTPStream::kStatusKey = ":status:"; // MUST be lowercase. - -HTTPStream::HTTPStream() - : mState(READY), - mUIDValid(false), - mSocket(-1), - mSSLContext(NULL), - mSSL(NULL) { -} - -HTTPStream::~HTTPStream() { - disconnect(); - - if (mSSLContext != NULL) { - SSL_CTX_free((SSL_CTX *)mSSLContext); - mSSLContext = NULL; - } -} - -void HTTPStream::setUID(uid_t uid) { - mUIDValid = true; - mUID = uid; -} - -static bool MakeSocketBlocking(int s, bool blocking) { - // Make socket non-blocking. - int flags = fcntl(s, F_GETFL, 0); - if (flags == -1) { - return false; - } - - if (blocking) { - flags &= ~O_NONBLOCK; - } else { - flags |= O_NONBLOCK; - } - - return fcntl(s, F_SETFL, flags) != -1; -} - -static status_t MyConnect( - int s, const struct sockaddr *addr, socklen_t addrlen) { - status_t result = UNKNOWN_ERROR; - - MakeSocketBlocking(s, false); - - if (connect(s, addr, addrlen) == 0) { - result = OK; - } else if (errno != EINPROGRESS) { - result = -errno; - } else { - for (;;) { - fd_set rs, ws; - FD_ZERO(&rs); - FD_ZERO(&ws); - FD_SET(s, &rs); - FD_SET(s, &ws); - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 100000ll; - - int nfds = ::select(s + 1, &rs, &ws, NULL, &tv); - - if (nfds < 0) { - if (errno == EINTR) { - continue; - } - - result = -errno; - break; - } - - if (FD_ISSET(s, &ws) && !FD_ISSET(s, &rs)) { - result = OK; - break; - } - - if (FD_ISSET(s, &rs) || FD_ISSET(s, &ws)) { - // Get the pending error. - int error = 0; - socklen_t errorLen = sizeof(error); - if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &errorLen) == -1) { - // Couldn't get the real error, so report why not. - result = -errno; - } else { - result = -error; - } - break; - } - - // Timeout expired. Try again. - } - } - - MakeSocketBlocking(s, true); - - return result; -} - -// Apparently under out linux closing a socket descriptor from one thread -// will not unblock a pending send/recv on that socket on another thread. -static ssize_t MySendReceive( - int s, void *data, size_t size, int flags, bool sendData) { - ssize_t result = 0; - - if (s < 0) { - return -1; - } - while (size > 0) { - fd_set rs, ws, es; - FD_ZERO(&rs); - FD_ZERO(&ws); - FD_ZERO(&es); - FD_SET(s, sendData ? &ws : &rs); - FD_SET(s, &es); - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 100000ll; - - int nfds = ::select( - s + 1, - sendData ? NULL : &rs, - sendData ? &ws : NULL, - &es, - &tv); - - if (nfds < 0) { - if (errno == EINTR) { - continue; - } - - result = -errno; - break; - } else if (nfds == 0) { - // timeout - - continue; - } - - CHECK_EQ(nfds, 1); - - ssize_t nbytes = - sendData ? send(s, data, size, flags) : recv(s, data, size, flags); - - if (nbytes < 0) { - if (errno == EINTR) { - continue; - } - - result = -errno; - break; - } else if (nbytes == 0) { - result = 0; - break; - } - - data = (uint8_t *)data + nbytes; - size -= nbytes; - - result = nbytes; - break; - } - - return result; -} - -static ssize_t MySend(int s, const void *data, size_t size, int flags) { - return MySendReceive( - s, const_cast<void *>(data), size, flags, true /* sendData */); -} - -static ssize_t MyReceive(int s, void *data, size_t size, int flags) { - return MySendReceive(s, data, size, flags, false /* sendData */); -} - -status_t HTTPStream::connect(const char *server, int port, bool https) { - if (port < 0) { - port = https ? 443 : 80; - } - - Mutex::Autolock autoLock(mLock); - - status_t err = OK; - - if (mState == CONNECTED) { - return ERROR_ALREADY_CONNECTED; - } - - if (port < 0 || port > (int) USHRT_MAX) { - return UNKNOWN_ERROR; - } - - char service[sizeof("65536")]; - sprintf(service, "%d", port); - struct addrinfo hints, *ai; - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; - hints.ai_socktype = SOCK_STREAM; - - int ret = getaddrinfo(server, service, &hints, &ai); - if (ret) { - return ERROR_UNKNOWN_HOST; - } - - CHECK_EQ(mSocket, -1); - - mState = CONNECTING; - status_t res = -1; - struct addrinfo *tmp; - for (tmp = ai; tmp; tmp = tmp->ai_next) { - mSocket = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol); - if (mSocket < 0) { - continue; - } - - if (mUIDValid) { - RegisterSocketUser(mSocket, mUID); - } - - setReceiveTimeout(30); // Time out reads after 30 secs by default. - - int s = mSocket; - - mLock.unlock(); - - res = MyConnect(s, tmp->ai_addr, tmp->ai_addrlen); - - mLock.lock(); - - if (mState != CONNECTING) { - close(s); - freeaddrinfo(ai); - return UNKNOWN_ERROR; - } - - if (res == OK) { - break; - } - - close(s); - } - - freeaddrinfo(ai); - - if (res != OK) { - close(mSocket); - mSocket = -1; - - mState = READY; - return res; - } - - if (https) { - CHECK(mSSL == NULL); - - if (mSSLContext == NULL) { - SSL_library_init(); - - mSSLContext = SSL_CTX_new(TLSv1_client_method()); - - if (mSSLContext == NULL) { - LOGE("failed to create SSL context"); - mState = READY; - return ERROR_IO; - } - } - - mSSL = SSL_new((SSL_CTX *)mSSLContext); - - if (mSSL == NULL) { - LOGE("failed to create SSL session"); - - mState = READY; - return ERROR_IO; - } - - int res = SSL_set_fd((SSL *)mSSL, mSocket); - - if (res == 1) { - res = SSL_connect((SSL *)mSSL); - } - - if (res != 1) { - SSL_free((SSL *)mSSL); - mSSL = NULL; - - LOGE("failed to connect over SSL"); - mState = READY; - - return ERROR_IO; - } - } - - mState = CONNECTED; - - return OK; -} - -status_t HTTPStream::disconnect() { - Mutex::Autolock autoLock(mLock); - - if (mState != CONNECTED && mState != CONNECTING) { - return ERROR_NOT_CONNECTED; - } - - if (mSSL != NULL) { - SSL_shutdown((SSL *)mSSL); - - SSL_free((SSL *)mSSL); - mSSL = NULL; - } - - CHECK(mSocket >= 0); - close(mSocket); - mSocket = -1; - - mState = READY; - - return OK; -} - -status_t HTTPStream::send(const char *data, size_t size) { - if (mState != CONNECTED) { - return ERROR_NOT_CONNECTED; - } - - while (size > 0) { - ssize_t n; - if (mSSL != NULL) { - n = SSL_write((SSL *)mSSL, data, size); - - if (n < 0) { - n = -SSL_get_error((SSL *)mSSL, n); - } - } else { - n = MySend(mSocket, data, size, 0); - } - - if (n < 0) { - disconnect(); - - return n; - } else if (n == 0) { - disconnect(); - - return ERROR_CONNECTION_LOST; - } - - size -= (size_t)n; - data += (size_t)n; - } - - return OK; -} - -status_t HTTPStream::send(const char *data) { - return send(data, strlen(data)); -} - -// A certain application spawns a local webserver that sends invalid responses, -// specifically it terminates header line with only a newline instead of the -// CRLF (carriage-return followed by newline) required by the HTTP specs. -// The workaround accepts both behaviours but could potentially break -// legitimate responses that use a single newline to "fold" headers, which is -// why it's not yet on by default. -#define WORKAROUND_FOR_MISSING_CR 1 - -status_t HTTPStream::receive_line(char *line, size_t size) { - if (mState != CONNECTED) { - return ERROR_NOT_CONNECTED; - } - - bool saw_CR = false; - size_t length = 0; - - for (;;) { - char c; - ssize_t n; - if (mSSL != NULL) { - n = SSL_read((SSL *)mSSL, &c, 1); - - if (n < 0) { - n = -SSL_get_error((SSL *)mSSL, n); - } - } else { - n = MyReceive(mSocket, &c, 1, 0); - } - - if (n < 0) { - disconnect(); - - return ERROR_IO; - } else if (n == 0) { - disconnect(); - - return ERROR_CONNECTION_LOST; - } - -#if WORKAROUND_FOR_MISSING_CR - if (c == '\n') { - // We have a complete line. - - line[saw_CR ? length - 1 : length] = '\0'; - return OK; - } -#else - if (saw_CR && c == '\n') { - // We have a complete line. - - line[length - 1] = '\0'; - return OK; - } -#endif - - saw_CR = (c == '\r'); - - if (length + 1 >= size) { - return ERROR_MALFORMED; - } - line[length++] = c; - } -} - -status_t HTTPStream::receive_header(int *http_status) { - *http_status = -1; - mHeaders.clear(); - - char line[2048]; - status_t err = receive_line(line, sizeof(line)); - if (err != OK) { - return err; - } - - mHeaders.add(AString(kStatusKey), AString(line)); - - char *spacePos = strchr(line, ' '); - if (spacePos == NULL) { - // Malformed response? - return UNKNOWN_ERROR; - } - - char *status_start = spacePos + 1; - char *status_end = status_start; - while (isdigit(*status_end)) { - ++status_end; - } - - if (status_end == status_start) { - // Malformed response, status missing? - return UNKNOWN_ERROR; - } - - memmove(line, status_start, status_end - status_start); - line[status_end - status_start] = '\0'; - - long tmp = strtol(line, NULL, 10); - if (tmp < 0 || tmp > 999) { - return UNKNOWN_ERROR; - } - - *http_status = (int)tmp; - - for (;;) { - err = receive_line(line, sizeof(line)); - if (err != OK) { - return err; - } - - if (*line == '\0') { - // Empty line signals the end of the header. - break; - } - - // puts(line); - - char *colonPos = strchr(line, ':'); - if (colonPos == NULL) { - AString key = line; - key.tolower(); - - mHeaders.add(key, AString()); - } else { - char *end_of_key = colonPos; - while (end_of_key > line && isspace(end_of_key[-1])) { - --end_of_key; - } - - char *start_of_value = colonPos + 1; - while (isspace(*start_of_value)) { - ++start_of_value; - } - - *end_of_key = '\0'; - - AString key = line; - key.tolower(); - - mHeaders.add(key, AString(start_of_value)); - } - } - - return OK; -} - -ssize_t HTTPStream::receive(void *data, size_t size) { - size_t total = 0; - while (total < size) { - ssize_t n; - if (mSSL != NULL) { - n = SSL_read((SSL *)mSSL, (char *)data + total, size - total); - - if (n < 0) { - n = -SSL_get_error((SSL *)mSSL, n); - } - } else { - n = MyReceive(mSocket, (char *)data + total, size - total, 0); - } - - if (n < 0) { - LOGE("recv failed, errno = %d (%s)", (int)n, strerror(-n)); - - disconnect(); - return (ssize_t)ERROR_IO; - } else if (n == 0) { - disconnect(); - - LOGE("recv failed, server is gone, total received: %d bytes", - total); - - return total == 0 ? (ssize_t)ERROR_CONNECTION_LOST : total; - } - - total += (size_t)n; - } - - return (ssize_t)total; -} - -bool HTTPStream::find_header_value(const AString &key, AString *value) const { - AString key_lower = key; - key_lower.tolower(); - - ssize_t index = mHeaders.indexOfKey(key_lower); - if (index < 0) { - value->clear(); - return false; - } - - *value = mHeaders.valueAt(index); - - return true; -} - -void HTTPStream::setReceiveTimeout(int seconds) { - if (seconds < 0) { - // Disable the timeout. - seconds = 0; - } - - struct timeval tv; - tv.tv_usec = 0; - tv.tv_sec = seconds; - CHECK_EQ(0, setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))); -} - -// static -void HTTPStream::RegisterSocketUser(int s, uid_t uid) { - // Lower bits MUST be 0. - static const uint64_t kTag = 0xdeadbeef00000000ll; - - AString line = StringPrintf("t %d %llu %d", s, kTag, uid); - - int fd = open("/proc/net/xt_qtaguid/ctrl", O_WRONLY); - write(fd, line.c_str(), line.size()); - close(fd); - fd = -1; -} - -} // namespace android - diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp deleted file mode 100644 index 2949767..0000000 --- a/media/libstagefright/NuHTTPDataSource.cpp +++ /dev/null @@ -1,560 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "NuHTTPDataSource" -#include <utils/Log.h> - -#include "include/NuHTTPDataSource.h" - -#include <cutils/properties.h> -#include <media/stagefright/foundation/ALooper.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaErrors.h> - -namespace android { - -static bool ParseSingleUnsignedLong( - const char *from, unsigned long *x) { - char *end; - *x = strtoul(from, &end, 10); - - if (end == from || *end != '\0') { - return false; - } - - return true; -} - -static bool ParseURL( - const char *url, String8 *host, unsigned *port, - String8 *path, bool *https) { - host->setTo(""); - *port = 0; - path->setTo(""); - - size_t hostStart; - if (!strncasecmp("http://", url, 7)) { - hostStart = 7; - *https = false; - } else if (!strncasecmp("https://", url, 8)) { - hostStart = 8; - *https = true; - } else { - return false; - } - - const char *slashPos = strchr(&url[hostStart], '/'); - - if (slashPos == NULL) { - host->setTo(&url[hostStart]); - path->setTo("/"); - } else { - host->setTo(&url[hostStart], slashPos - &url[hostStart]); - path->setTo(slashPos); - } - - const char *colonPos = strchr(host->string(), ':'); - - if (colonPos != NULL) { - unsigned long x; - if (!ParseSingleUnsignedLong(colonPos + 1, &x) || x >= 65536) { - return false; - } - - *port = x; - - size_t colonOffset = colonPos - host->string(); - String8 tmp(host->string(), colonOffset); - *host = tmp; - } else { - *port = (*https) ? 443 : 80; - } - - return true; -} - -NuHTTPDataSource::NuHTTPDataSource(uint32_t flags) - : mFlags(flags), - mState(DISCONNECTED), - mPort(0), - mHTTPS(false), - mOffset(0), - mContentLength(0), - mContentLengthValid(false), - mHasChunkedTransferEncoding(false), - mChunkDataBytesLeft(0), - mDecryptHandle(NULL), - mDrmManagerClient(NULL) { -} - -NuHTTPDataSource::~NuHTTPDataSource() { - if (mDecryptHandle != NULL) { - // To release mDecryptHandle - CHECK(mDrmManagerClient); - mDrmManagerClient->closeDecryptSession(mDecryptHandle); - mDecryptHandle = NULL; - } - - if (mDrmManagerClient != NULL) { - delete mDrmManagerClient; - mDrmManagerClient = NULL; - } -} - -status_t NuHTTPDataSource::connect( - const char *uri, - const KeyedVector<String8, String8> *overrides, - off64_t offset) { - String8 headers; - MakeFullHeaders(overrides, &headers); - - return connect(uri, headers, offset); -} - -status_t NuHTTPDataSource::connect( - const char *uri, - const String8 &headers, - off64_t offset) { - String8 host, path; - unsigned port; - - mUri = uri; - mContentType = String8("application/octet-stream"); - - bool https; - if (!ParseURL(uri, &host, &port, &path, &https)) { - return ERROR_MALFORMED; - } - - uid_t uid; - if (getUID(&uid)) { - mHTTP.setUID(uid); - } - - return connect(host, port, path, https, headers, offset); -} - -static bool IsRedirectStatusCode(int httpStatus) { - return httpStatus == 301 || httpStatus == 302 - || httpStatus == 303 || httpStatus == 307; -} - -status_t NuHTTPDataSource::connect( - const char *host, unsigned port, const char *path, - bool https, - const String8 &headers, - off64_t offset) { - if (!(mFlags & kFlagIncognito)) { - LOGI("connect to %s:%u%s @%lld", host, port, path, offset); - } else { - LOGI("connect to <URL suppressed> @%lld", offset); - } - - bool needsToReconnect = true; - - if (mState == CONNECTED && host == mHost && port == mPort - && https == mHTTPS && offset == mOffset) { - if (mContentLengthValid && mOffset == mContentLength) { - LOGI("Didn't have to reconnect, old one's still good."); - needsToReconnect = false; - } - } - - mHost = host; - mPort = port; - mPath = path; - mHTTPS = https; - mHeaders = headers; - - status_t err = OK; - - mState = CONNECTING; - - if (needsToReconnect) { - mHTTP.disconnect(); - err = mHTTP.connect(host, port, https); - } - - if (err != OK) { - mState = DISCONNECTED; - } else if (mState != CONNECTING) { - err = UNKNOWN_ERROR; - } else { - mState = CONNECTED; - - mOffset = offset; - mContentLength = 0; - mContentLengthValid = false; - - String8 request("GET "); - request.append(mPath); - request.append(" HTTP/1.1\r\n"); - request.append("Host: "); - request.append(mHost); - if (mPort != 80) { - request.append(StringPrintf(":%u", mPort).c_str()); - } - request.append("\r\n"); - - if (offset != 0) { - char rangeHeader[128]; - sprintf(rangeHeader, "Range: bytes=%lld-\r\n", offset); - request.append(rangeHeader); - } - - request.append(mHeaders); - request.append("\r\n"); - - int httpStatus; - if ((err = mHTTP.send(request.string(), request.size())) != OK - || (err = mHTTP.receive_header(&httpStatus)) != OK) { - mHTTP.disconnect(); - mState = DISCONNECTED; - return err; - } - - if (IsRedirectStatusCode(httpStatus)) { - AString value; - CHECK(mHTTP.find_header_value("Location", &value)); - - mState = DISCONNECTED; - - mHTTP.disconnect(); - - return connect(value.c_str(), headers, offset); - } - - if (httpStatus < 200 || httpStatus >= 300) { - mState = DISCONNECTED; - mHTTP.disconnect(); - - return ERROR_IO; - } - - mHasChunkedTransferEncoding = false; - - { - AString value; - if (mHTTP.find_header_value("Transfer-Encoding", &value)) { - // We don't currently support any transfer encodings but - // chunked. - - if (!strcasecmp(value.c_str(), "chunked")) { - LOGI("Chunked transfer encoding applied."); - mHasChunkedTransferEncoding = true; - mChunkDataBytesLeft = 0; - } else { - mState = DISCONNECTED; - mHTTP.disconnect(); - - LOGE("We don't support '%s' transfer encoding.", value.c_str()); - - return ERROR_UNSUPPORTED; - } - } - } - - { - AString value; - if (mHTTP.find_header_value("Content-Type", &value)) { - mContentType = String8(value.c_str()); - } else { - mContentType = String8("application/octet-stream"); - } - } - - applyTimeoutResponse(); - - if (offset == 0) { - AString value; - unsigned long x; - if (mHTTP.find_header_value(AString("Content-Length"), &value) - && ParseSingleUnsignedLong(value.c_str(), &x)) { - mContentLength = (off64_t)x; - mContentLengthValid = true; - } else { - LOGW("Server did not give us the content length!"); - } - } else { - if (httpStatus != 206 /* Partial Content */) { - // We requested a range but the server didn't support that. - LOGE("We requested a range but the server didn't " - "support that."); - return ERROR_UNSUPPORTED; - } - - AString value; - unsigned long x; - if (mHTTP.find_header_value(AString("Content-Range"), &value)) { - const char *slashPos = strchr(value.c_str(), '/'); - if (slashPos != NULL - && ParseSingleUnsignedLong(slashPos + 1, &x)) { - mContentLength = x; - mContentLengthValid = true; - } - } - } - } - - return err; -} - -void NuHTTPDataSource::disconnect() { - if (mState == CONNECTING || mState == CONNECTED) { - mHTTP.disconnect(); - } - mState = DISCONNECTED; -} - -status_t NuHTTPDataSource::initCheck() const { - return mState == CONNECTED ? OK : NO_INIT; -} - -ssize_t NuHTTPDataSource::internalRead(void *data, size_t size) { - if (!mHasChunkedTransferEncoding) { - return mHTTP.receive(data, size); - } - - if (mChunkDataBytesLeft < 0) { - return 0; - } else if (mChunkDataBytesLeft == 0) { - char line[1024]; - status_t err = mHTTP.receive_line(line, sizeof(line)); - - if (err != OK) { - return err; - } - - LOGV("line = '%s'", line); - - char *end; - unsigned long n = strtoul(line, &end, 16); - - if (end == line || (*end != ';' && *end != '\0')) { - LOGE("malformed HTTP chunk '%s'", line); - return ERROR_MALFORMED; - } - - mChunkDataBytesLeft = n; - LOGV("chunk data size = %lu", n); - - if (mChunkDataBytesLeft == 0) { - mChunkDataBytesLeft = -1; - return 0; - } - - // fall through - } - - if (size > (size_t)mChunkDataBytesLeft) { - size = mChunkDataBytesLeft; - } - - ssize_t n = mHTTP.receive(data, size); - - if (n < 0) { - return n; - } - - mChunkDataBytesLeft -= (size_t)n; - - if (mChunkDataBytesLeft == 0) { - char line[1024]; - status_t err = mHTTP.receive_line(line, sizeof(line)); - - if (err != OK) { - return err; - } - - if (line[0] != '\0') { - LOGE("missing HTTP chunk terminator."); - return ERROR_MALFORMED; - } - } - - return n; -} - -ssize_t NuHTTPDataSource::readAt(off64_t offset, void *data, size_t size) { - LOGV("readAt offset %ld, size %d", offset, size); - - Mutex::Autolock autoLock(mLock); - - if (offset != mOffset) { - String8 host = mHost; - String8 path = mPath; - String8 headers = mHeaders; - status_t err = connect(host, mPort, path, mHTTPS, headers, offset); - - if (err != OK) { - return err; - } - } - - if (mContentLengthValid) { - size_t avail = - (offset >= mContentLength) ? 0 : mContentLength - offset; - - if (size > avail) { - size = avail; - } - } - - size_t numBytesRead = 0; - while (numBytesRead < size) { - int64_t startTimeUs = ALooper::GetNowUs(); - - ssize_t n = - internalRead((uint8_t *)data + numBytesRead, size - numBytesRead); - - if (n < 0) { - if (numBytesRead == 0 || mContentLengthValid) { - return n; - } - - // If there was an error we want to at least return the data - // we've already successfully read. The next call to read will - // then return the error. - n = 0; - } - - int64_t delayUs = ALooper::GetNowUs() - startTimeUs; - addBandwidthMeasurement(n, delayUs); - - numBytesRead += (size_t)n; - - if (n == 0) { - if (mContentLengthValid) { - // We know the content length and made sure not to read beyond - // it and yet the server closed the connection on us. - return ERROR_IO; - } - - break; - } - } - - mOffset += numBytesRead; - - return numBytesRead; -} - -status_t NuHTTPDataSource::getSize(off64_t *size) { - *size = 0; - - if (mState != CONNECTED) { - return ERROR_IO; - } - - if (mContentLengthValid) { - *size = mContentLength; - return OK; - } - - return ERROR_UNSUPPORTED; -} - -uint32_t NuHTTPDataSource::flags() { - return kWantsPrefetching | kIsHTTPBasedSource; -} - -// static -void NuHTTPDataSource::MakeFullHeaders( - const KeyedVector<String8, String8> *overrides, String8 *headers) { - headers->setTo(""); - - headers->append("User-Agent: stagefright/1.1 (Linux;Android "); - -#if (PROPERTY_VALUE_MAX < 8) -#error "PROPERTY_VALUE_MAX must be at least 8" -#endif - - char value[PROPERTY_VALUE_MAX]; - property_get("ro.build.version.release", value, "Unknown"); - headers->append(value); - headers->append(")\r\n"); - - if (overrides == NULL) { - return; - } - - for (size_t i = 0; i < overrides->size(); ++i) { - String8 line; - line.append(overrides->keyAt(i)); - line.append(": "); - line.append(overrides->valueAt(i)); - line.append("\r\n"); - - headers->append(line); - } -} - -void NuHTTPDataSource::applyTimeoutResponse() { - AString timeout; - if (mHTTP.find_header_value("X-SocketTimeout", &timeout)) { - const char *s = timeout.c_str(); - char *end; - long tmp = strtol(s, &end, 10); - if (end == s || *end != '\0') { - LOGW("Illegal X-SocketTimeout value given."); - return; - } - - LOGI("overriding default timeout, new timeout is %ld seconds", tmp); - mHTTP.setReceiveTimeout(tmp); - } -} - -sp<DecryptHandle> NuHTTPDataSource::DrmInitialization() { - if (mDrmManagerClient == NULL) { - mDrmManagerClient = new DrmManagerClient(); - } - - if (mDrmManagerClient == NULL) { - return NULL; - } - - if (mDecryptHandle == NULL) { - /* Note if redirect occurs, mUri is the redirect uri instead of the - * original one - */ - mDecryptHandle = mDrmManagerClient->openDecryptSession(mUri); - } - - if (mDecryptHandle == NULL) { - delete mDrmManagerClient; - mDrmManagerClient = NULL; - } - - return mDecryptHandle; -} - -void NuHTTPDataSource::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) { - handle = mDecryptHandle; - - *client = mDrmManagerClient; -} - -String8 NuHTTPDataSource::getUri() { - return mUri; -} - -String8 NuHTTPDataSource::getMIMEType() const { - return mContentType; -} - -} // namespace android diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 3b05752..b7b0dc0 100755 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -18,20 +18,11 @@ #define LOG_TAG "OMXCodec" #include <utils/Log.h> -#include "include/AACDecoder.h" #include "include/AACEncoder.h" -#include "include/AMRNBDecoder.h" #include "include/AMRNBEncoder.h" -#include "include/AMRWBDecoder.h" #include "include/AMRWBEncoder.h" -#include "include/AVCDecoder.h" #include "include/AVCEncoder.h" -#include "include/G711Decoder.h" -#include "include/M4vH263Decoder.h" #include "include/M4vH263Encoder.h" -#include "include/MP3Decoder.h" -#include "include/VorbisDecoder.h" -#include "include/VPXDecoder.h" #include "include/ESDS.h" @@ -53,10 +44,6 @@ #include <OMX_Audio.h> #include <OMX_Component.h> -#if HAVE_SOFTWARE_DECODERS -#include "include/ThreadedSource.h" -#endif - #include "include/avc_utils.h" namespace android { @@ -79,24 +66,6 @@ FACTORY_CREATE_ENCODER(AACEncoder) FACTORY_CREATE_ENCODER(AVCEncoder) FACTORY_CREATE_ENCODER(M4vH263Encoder) -#if HAVE_SOFTWARE_DECODERS - -#define FACTORY_CREATE(name) \ -static sp<MediaSource> Make##name(const sp<MediaSource> &source) { \ - return new name(source); \ -} - -FACTORY_CREATE(AMRNBDecoder) -FACTORY_CREATE(AMRWBDecoder) -FACTORY_CREATE(AACDecoder) -FACTORY_CREATE(AVCDecoder) -FACTORY_CREATE(G711Decoder) -FACTORY_CREATE(MP3Decoder) -FACTORY_CREATE(M4vH263Decoder) -FACTORY_CREATE(VorbisDecoder) -FACTORY_CREATE(VPXDecoder) -#endif - static sp<MediaSource> InstantiateSoftwareEncoder( const char *name, const sp<MediaSource> &source, const sp<MetaData> &meta) { @@ -122,40 +91,6 @@ static sp<MediaSource> InstantiateSoftwareEncoder( return NULL; } -static sp<MediaSource> InstantiateSoftwareCodec( - const char *name, const sp<MediaSource> &source) { -#if HAVE_SOFTWARE_DECODERS - struct FactoryInfo { - const char *name; - sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &); - }; - - static const FactoryInfo kFactoryInfo[] = { - FACTORY_REF(AMRNBDecoder) - FACTORY_REF(AMRWBDecoder) - FACTORY_REF(AACDecoder) - FACTORY_REF(AVCDecoder) - FACTORY_REF(G711Decoder) - FACTORY_REF(MP3Decoder) - FACTORY_REF(M4vH263Decoder) - FACTORY_REF(VorbisDecoder) - FACTORY_REF(VPXDecoder) - }; - for (size_t i = 0; - i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) { - if (!strcmp(name, kFactoryInfo[i].name)) { - if (!strcmp(name, "VPXDecoder")) { - return new ThreadedSource( - (*kFactoryInfo[i].CreateFunc)(source)); - } - return (*kFactoryInfo[i].CreateFunc)(source); - } - } -#endif - - return NULL; -} - #undef FACTORY_REF #undef FACTORY_CREATE @@ -163,23 +98,17 @@ static const CodecInfo kDecoderInfo[] = { { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" }, // { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" }, { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.google.mp3.decoder" }, - { MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" }, // { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" }, // { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amr.decoder" }, { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.decoder" }, - { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder" }, // { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amrwb.decoder" }, { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" }, { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.decoder" }, - { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBDecoder" }, // { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.Nvidia.aac.decoder" }, { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" }, { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.decoder" }, - { MEDIA_MIMETYPE_AUDIO_AAC, "AACDecoder" }, { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "OMX.google.g711.alaw.decoder" }, - { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "G711Decoder" }, { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "OMX.google.g711.mlaw.decoder" }, - { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "G711Decoder" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.DECODER" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.decode" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.decoder.mpeg4" }, @@ -187,14 +116,12 @@ static const CodecInfo kDecoderInfo[] = { { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Decoder" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.google.mpeg4.decoder" }, - { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.DUCATI1.VIDEO.DECODER" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.decode" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.decoder.h263" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Decoder" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.google.h263.decoder" }, - { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Decoder" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.DUCATI1.VIDEO.DECODER" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.decode" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.decoder.avc" }, @@ -203,11 +130,8 @@ static const CodecInfo kDecoderInfo[] = { { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.SEC.AVC.Decoder" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.google.h264.decoder" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.google.avc.decoder" }, - { MEDIA_MIMETYPE_VIDEO_AVC, "AVCDecoder" }, { MEDIA_MIMETYPE_AUDIO_VORBIS, "OMX.google.vorbis.decoder" }, - { MEDIA_MIMETYPE_AUDIO_VORBIS, "VorbisDecoder" }, { MEDIA_MIMETYPE_VIDEO_VPX, "OMX.google.vpx.decoder" }, - { MEDIA_MIMETYPE_VIDEO_VPX, "VPXDecoder" }, { MEDIA_MIMETYPE_VIDEO_MPEG2, "OMX.Nvidia.mpeg2v.decode" }, }; @@ -518,14 +442,15 @@ sp<MediaSource> OMXCodec::Create( for (size_t i = 0; i < matchingCodecs.size(); ++i) { componentName = matchingCodecs[i].string(); - sp<MediaSource> softwareCodec = createEncoder? - InstantiateSoftwareEncoder(componentName, source, meta): - InstantiateSoftwareCodec(componentName, source); + if (createEncoder) { + sp<MediaSource> softwareCodec = + InstantiateSoftwareEncoder(componentName, source, meta); - if (softwareCodec != NULL) { - LOGV("Successfully allocated software codec '%s'", componentName); + if (softwareCodec != NULL) { + LOGV("Successfully allocated software codec '%s'", componentName); - return softwareCodec; + return softwareCodec; + } } LOGV("Attempting to allocate OMX node '%s'", componentName); @@ -4430,12 +4355,9 @@ status_t QueryCodecs( if (strncmp(componentName, "OMX.", 4)) { // Not an OpenMax component but a software codec. -#if HAVE_SOFTWARE_DECODERS results->push(); CodecCapabilities *caps = &results->editItemAt(results->size() - 1); caps->mComponentName = componentName; -#endif - continue; } diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp deleted file mode 100644 index 783f2d0..0000000 --- a/media/libstagefright/ShoutcastSource.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/HTTPStream.h" - -#include <stdlib.h> - -#include <media/stagefright/MediaBuffer.h> -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/ShoutcastSource.h> - -namespace android { - -ShoutcastSource::ShoutcastSource(HTTPStream *http) - : mHttp(http), - mMetaDataOffset(0), - mBytesUntilMetaData(0), - mGroup(NULL), - mStarted(false) { - AString metaint; - if (mHttp->find_header_value("icy-metaint", &metaint)) { - char *end; - const char *start = metaint.c_str(); - mMetaDataOffset = strtol(start, &end, 10); - CHECK(end > start && *end == '\0'); - CHECK(mMetaDataOffset > 0); - - mBytesUntilMetaData = mMetaDataOffset; - } -} - -ShoutcastSource::~ShoutcastSource() { - if (mStarted) { - stop(); - } - - delete mHttp; - mHttp = NULL; -} - -status_t ShoutcastSource::start(MetaData *) { - CHECK(!mStarted); - - mGroup = new MediaBufferGroup; - mGroup->add_buffer(new MediaBuffer(4096)); // XXX - - mStarted = true; - - return OK; -} - -status_t ShoutcastSource::stop() { - CHECK(mStarted); - - delete mGroup; - mGroup = NULL; - - mStarted = false; - - return OK; -} - -sp<MetaData> ShoutcastSource::getFormat() { - sp<MetaData> meta = new MetaData; - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); - meta->setInt32(kKeySampleRate, 44100); - meta->setInt32(kKeyChannelCount, 2); // XXX - - return meta; -} - -status_t ShoutcastSource::read( - MediaBuffer **out, const ReadOptions *options) { - CHECK(mStarted); - - *out = NULL; - - int64_t seekTimeUs; - ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { - return ERROR_UNSUPPORTED; - } - - MediaBuffer *buffer; - status_t err = mGroup->acquire_buffer(&buffer); - if (err != OK) { - return err; - } - - *out = buffer; - - size_t num_bytes = buffer->size(); - if (mMetaDataOffset > 0 && num_bytes > mBytesUntilMetaData) { - num_bytes = mBytesUntilMetaData; - } - - ssize_t n = mHttp->receive(buffer->data(), num_bytes); - - if (n <= 0) { - return (status_t)n; - } - - buffer->set_range(0, n); - - mBytesUntilMetaData -= (size_t)n; - - if (mBytesUntilMetaData == 0) { - unsigned char num_16_byte_blocks = 0; - n = mHttp->receive((char *)&num_16_byte_blocks, 1); - CHECK_EQ(n, 1); - - char meta[255 * 16]; - size_t meta_size = num_16_byte_blocks * 16; - size_t meta_length = 0; - while (meta_length < meta_size) { - n = mHttp->receive(&meta[meta_length], meta_size - meta_length); - if (n <= 0) { - return (status_t)n; - } - - meta_length += (size_t) n; - } - - while (meta_length > 0 && meta[meta_length - 1] == '\0') { - --meta_length; - } - - if (meta_length > 0) { - // Technically we should probably attach this meta data to the - // next buffer. XXX - buffer->meta_data()->setData('shou', 'shou', meta, meta_length); - } - - mBytesUntilMetaData = mMetaDataOffset; - } - - return OK; -} - -} // namespace android - diff --git a/media/libstagefright/ThreadedSource.cpp b/media/libstagefright/ThreadedSource.cpp deleted file mode 100644 index 38c6e2d..0000000 --- a/media/libstagefright/ThreadedSource.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "ThreadedSource" -//#define LOG_NDEBUG 0 -#include <utils/Log.h> - -#include "include/ThreadedSource.h" - -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/foundation/AMessage.h> -#include <media/stagefright/MediaBuffer.h> -#include <media/stagefright/MetaData.h> - -namespace android { - -static const size_t kMaxQueueSize = 2; - -ThreadedSource::ThreadedSource(const sp<MediaSource> &source) - : mSource(source), - mReflector(new AHandlerReflector<ThreadedSource>(this)), - mLooper(new ALooper), - mStarted(false) { - mLooper->registerHandler(mReflector); -} - -ThreadedSource::~ThreadedSource() { - if (mStarted) { - stop(); - } -} - -status_t ThreadedSource::start(MetaData *params) { - CHECK(!mStarted); - - status_t err = mSource->start(params); - - if (err != OK) { - return err; - } - - mFinalResult = OK; - mSeekTimeUs = -1; - mDecodePending = false; - - Mutex::Autolock autoLock(mLock); - postDecodeMore_l(); - - CHECK_EQ(mLooper->start(), (status_t)OK); - - mStarted = true; - - return OK; -} - -status_t ThreadedSource::stop() { - CHECK(mStarted); - - CHECK_EQ(mLooper->stop(), (status_t)OK); - - Mutex::Autolock autoLock(mLock); - clearQueue_l(); - - status_t err = mSource->stop(); - - mStarted = false; - - return err; -} - -sp<MetaData> ThreadedSource::getFormat() { - return mSource->getFormat(); -} - -status_t ThreadedSource::read( - MediaBuffer **buffer, const ReadOptions *options) { - *buffer = NULL; - - Mutex::Autolock autoLock(mLock); - - int64_t seekTimeUs; - ReadOptions::SeekMode seekMode; - if (options && options->getSeekTo(&seekTimeUs, &seekMode)) { - int32_t seekComplete = 0; - - sp<AMessage> msg = new AMessage(kWhatSeek, mReflector->id()); - msg->setInt64("timeUs", seekTimeUs); - msg->setInt32("mode", seekMode); - msg->setPointer("complete", &seekComplete); - msg->post(); - - while (!seekComplete) { - mCondition.wait(mLock); - } - } - - while (mQueue.empty() && mFinalResult == OK) { - mCondition.wait(mLock); - } - - if (!mQueue.empty()) { - *buffer = *mQueue.begin(); - mQueue.erase(mQueue.begin()); - - if (mFinalResult == OK) { - postDecodeMore_l(); - } - - return OK; - } - - return mFinalResult; -} - -void ThreadedSource::onMessageReceived(const sp<AMessage> &msg) { - switch (msg->what()) { - case kWhatSeek: - { - CHECK(msg->findInt64("timeUs", &mSeekTimeUs)); - CHECK_GE(mSeekTimeUs, 0ll); - - int32_t x; - CHECK(msg->findInt32("mode", &x)); - mSeekMode = (ReadOptions::SeekMode)x; - - int32_t *seekComplete; - CHECK(msg->findPointer("complete", (void **)&seekComplete)); - - Mutex::Autolock autoLock(mLock); - clearQueue_l(); - mFinalResult = OK; - - *seekComplete = 1; - mCondition.signal(); - - postDecodeMore_l(); - break; - } - - case kWhatDecodeMore: - { - { - Mutex::Autolock autoLock(mLock); - mDecodePending = false; - - if (mQueue.size() == kMaxQueueSize) { - break; - } - } - - MediaBuffer *buffer; - ReadOptions options; - if (mSeekTimeUs >= 0) { - options.setSeekTo(mSeekTimeUs, mSeekMode); - mSeekTimeUs = -1ll; - } - status_t err = mSource->read(&buffer, &options); - - Mutex::Autolock autoLock(mLock); - - if (err != OK) { - mFinalResult = err; - } else { - mQueue.push_back(buffer); - - if (mQueue.size() < kMaxQueueSize) { - postDecodeMore_l(); - } - } - - mCondition.signal(); - break; - } - - default: - TRESPASS(); - break; - } -} - -void ThreadedSource::postDecodeMore_l() { - if (mDecodePending) { - return; - } - - mDecodePending = true; - (new AMessage(kWhatDecodeMore, mReflector->id()))->post(); -} - -void ThreadedSource::clearQueue_l() { - while (!mQueue.empty()) { - MediaBuffer *buffer = *mQueue.begin(); - mQueue.erase(mQueue.begin()); - - buffer->release(); - buffer = NULL; - } -} - -} // namespace android diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp deleted file mode 100644 index d2e3eaa..0000000 --- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "AACDecoder.h" -#define LOG_TAG "AACDecoder" - -#include "../../include/ESDS.h" - -#include "pvmp4audiodecoder_api.h" - -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MetaData.h> - -namespace android { - -AACDecoder::AACDecoder(const sp<MediaSource> &source) - : mSource(source), - mStarted(false), - mBufferGroup(NULL), - mConfig(new tPVMP4AudioDecoderExternal), - mDecoderBuf(NULL), - mAnchorTimeUs(0), - mNumSamplesOutput(0), - mInputBuffer(NULL) { - - sp<MetaData> srcFormat = mSource->getFormat(); - - int32_t sampleRate; - CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate)); - - mMeta = new MetaData; - mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); - - // We'll always output stereo, regardless of how many channels are - // present in the input due to decoder limitations. - mMeta->setInt32(kKeyChannelCount, 2); - mMeta->setInt32(kKeySampleRate, sampleRate); - - int64_t durationUs; - if (srcFormat->findInt64(kKeyDuration, &durationUs)) { - mMeta->setInt64(kKeyDuration, durationUs); - } - mMeta->setCString(kKeyDecoderComponent, "AACDecoder"); - - mInitCheck = initCheck(); -} - -status_t AACDecoder::initCheck() { - memset(mConfig, 0, sizeof(tPVMP4AudioDecoderExternal)); - mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED; - mConfig->aacPlusEnabled = 1; - - // The software decoder doesn't properly support mono output on - // AACplus files. Always output stereo. - mConfig->desiredChannels = 2; - - UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements(); - mDecoderBuf = malloc(memRequirements); - - status_t err = PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf); - if (err != MP4AUDEC_SUCCESS) { - LOGE("Failed to initialize MP4 audio decoder"); - return UNKNOWN_ERROR; - } - - uint32_t type; - const void *data; - size_t size; - sp<MetaData> meta = mSource->getFormat(); - if (meta->findData(kKeyESDS, &type, &data, &size)) { - ESDS esds((const char *)data, size); - CHECK_EQ(esds.InitCheck(), (status_t)OK); - - const void *codec_specific_data; - size_t codec_specific_data_size; - esds.getCodecSpecificInfo( - &codec_specific_data, &codec_specific_data_size); - - mConfig->pInputBuffer = (UChar *)codec_specific_data; - mConfig->inputBufferCurrentLength = codec_specific_data_size; - mConfig->inputBufferMaxLength = 0; - - if (PVMP4AudioDecoderConfig(mConfig, mDecoderBuf) - != MP4AUDEC_SUCCESS) { - return ERROR_UNSUPPORTED; - } - } - return OK; -} - -AACDecoder::~AACDecoder() { - if (mStarted) { - stop(); - } - - delete mConfig; - mConfig = NULL; -} - -status_t AACDecoder::start(MetaData *params) { - CHECK(!mStarted); - - mBufferGroup = new MediaBufferGroup; - mBufferGroup->add_buffer(new MediaBuffer(4096 * 2)); - - mSource->start(); - - mAnchorTimeUs = 0; - mNumSamplesOutput = 0; - mStarted = true; - mNumDecodedBuffers = 0; - mUpsamplingFactor = 2; - - return OK; -} - -status_t AACDecoder::stop() { - CHECK(mStarted); - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - free(mDecoderBuf); - mDecoderBuf = NULL; - - delete mBufferGroup; - mBufferGroup = NULL; - - mSource->stop(); - - mStarted = false; - - return OK; -} - -sp<MetaData> AACDecoder::getFormat() { - return mMeta; -} - -status_t AACDecoder::read( - MediaBuffer **out, const ReadOptions *options) { - status_t err; - - *out = NULL; - - int64_t seekTimeUs; - ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { - CHECK(seekTimeUs >= 0); - - mNumSamplesOutput = 0; - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - // Make sure that the next buffer output does not still - // depend on fragments from the last one decoded. - PVMP4AudioDecoderResetBuffer(mDecoderBuf); - } else { - seekTimeUs = -1; - } - - if (mInputBuffer == NULL) { - err = mSource->read(&mInputBuffer, options); - - if (err != OK) { - return err; - } - - int64_t timeUs; - if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { - mAnchorTimeUs = timeUs; - mNumSamplesOutput = 0; - } else { - // We must have a new timestamp after seeking. - CHECK(seekTimeUs < 0); - } - } - - MediaBuffer *buffer; - CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK); - - mConfig->pInputBuffer = - (UChar *)mInputBuffer->data() + mInputBuffer->range_offset(); - - mConfig->inputBufferCurrentLength = mInputBuffer->range_length(); - mConfig->inputBufferMaxLength = 0; - mConfig->inputBufferUsedLength = 0; - mConfig->remainderBits = 0; - - mConfig->pOutputBuffer = static_cast<Int16 *>(buffer->data()); - mConfig->pOutputBuffer_plus = &mConfig->pOutputBuffer[2048]; - mConfig->repositionFlag = false; - - Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf); - - /* - * AAC+/eAAC+ streams can be signalled in two ways: either explicitly - * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual - * rate system and the sampling rate in the final output is actually - * doubled compared with the core AAC decoder sampling rate. - * - * Explicit signalling is done by explicitly defining SBR audio object - * type in the bitstream. Implicit signalling is done by embedding - * SBR content in AAC extension payload specific to SBR, and hence - * requires an AAC decoder to perform pre-checks on actual audio frames. - * - * Thus, we could not say for sure whether a stream is - * AAC+/eAAC+ until the first data frame is decoded. - */ - if (++mNumDecodedBuffers <= 2) { - LOGV("audio/extended audio object type: %d + %d", - mConfig->audioObjectType, mConfig->extendedAudioObjectType); - LOGV("aac+ upsampling factor: %d desired channels: %d", - mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels); - - CHECK(mNumDecodedBuffers > 0); - - if (decoderErr != MP4AUDEC_SUCCESS) { - // If decoding fails this early, the fields in mConfig may - // not be valid and we cannot recover. - - LOGE("Unable to decode aac content, decoder returned error %d", - decoderErr); - - buffer->release(); - buffer = NULL; - - mInputBuffer->release(); - mInputBuffer = NULL; - - return ERROR_UNSUPPORTED; - } - - if (mNumDecodedBuffers == 1) { - mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor; - // Check on the sampling rate to see whether it is changed. - int32_t sampleRate; - CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate)); - if (mConfig->samplingRate != sampleRate) { - mMeta->setInt32(kKeySampleRate, mConfig->samplingRate); - LOGW("Sample rate was %d Hz, but now is %d Hz", - sampleRate, mConfig->samplingRate); - buffer->release(); - mInputBuffer->release(); - mInputBuffer = NULL; - return INFO_FORMAT_CHANGED; - } - } else { // mNumDecodedBuffers == 2 - if (mConfig->extendedAudioObjectType == MP4AUDIO_AAC_LC || - mConfig->extendedAudioObjectType == MP4AUDIO_LTP) { - if (mUpsamplingFactor == 2) { - // The stream turns out to be not aacPlus mode anyway - LOGW("Disable AAC+/eAAC+ since extended audio object type is %d", - mConfig->extendedAudioObjectType); - mConfig->aacPlusEnabled = 0; - } - } else { - if (mUpsamplingFactor == 1) { - // aacPlus mode does not buy us anything, but to cause - // 1. CPU load to increase, and - // 2. a half speed of decoding - LOGW("Disable AAC+/eAAC+ since upsampling factor is 1"); - mConfig->aacPlusEnabled = 0; - } - } - } - } - - size_t numOutBytes = - mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels; - if (mUpsamplingFactor == 2) { - if (mConfig->desiredChannels == 1) { - memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2); - } - numOutBytes *= 2; - } - - if (decoderErr != MP4AUDEC_SUCCESS) { - LOGW("AAC decoder returned error %d, substituting silence", decoderErr); - - memset(buffer->data(), 0, numOutBytes); - - // Discard input buffer. - mInputBuffer->release(); - mInputBuffer = NULL; - - // fall through - } - - buffer->set_range(0, numOutBytes); - - if (mInputBuffer != NULL) { - mInputBuffer->set_range( - mInputBuffer->range_offset() + mConfig->inputBufferUsedLength, - mInputBuffer->range_length() - mConfig->inputBufferUsedLength); - - if (mInputBuffer->range_length() == 0) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - } - - buffer->meta_data()->setInt64( - kKeyTime, - mAnchorTimeUs - + (mNumSamplesOutput * 1000000) / mConfig->samplingRate); - - mNumSamplesOutput += mConfig->frameLength * mUpsamplingFactor; - - *out = buffer; - - return OK; -} - -} // namespace android diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk index 359a2ec..20c7bc0 100644 --- a/media/libstagefright/codecs/aacdec/Android.mk +++ b/media/libstagefright/codecs/aacdec/Android.mk @@ -143,7 +143,6 @@ LOCAL_SRC_FILES := \ unpack_idx.cpp \ window_tables_fxp.cpp \ pvmp4setaudioconfig.cpp \ - AACDecoder.cpp \ LOCAL_CFLAGS := -DAAC_PLUS -DHQ_SBR -DPARAMETRICSTEREO -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF= -DOSCL_UNUSED_ARG= diff --git a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp deleted file mode 100644 index a11d46b..0000000 --- a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "AMRNBDecoder" -#include <utils/Log.h> - -#include "AMRNBDecoder.h" - -#include "gsmamr_dec.h" - -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MetaData.h> - -namespace android { - -static const int32_t kNumSamplesPerFrame = 160; -static const int32_t kSampleRate = 8000; - -AMRNBDecoder::AMRNBDecoder(const sp<MediaSource> &source) - : mSource(source), - mStarted(false), - mBufferGroup(NULL), - mState(NULL), - mAnchorTimeUs(0), - mNumSamplesOutput(0), - mInputBuffer(NULL) { -} - -AMRNBDecoder::~AMRNBDecoder() { - if (mStarted) { - stop(); - } -} - -status_t AMRNBDecoder::start(MetaData *params) { - CHECK(!mStarted); - - mBufferGroup = new MediaBufferGroup; - mBufferGroup->add_buffer( - new MediaBuffer(kNumSamplesPerFrame * sizeof(int16_t))); - - CHECK_EQ(GSMInitDecode(&mState, (Word8 *)"AMRNBDecoder"), 0); - - mSource->start(); - - mAnchorTimeUs = 0; - mNumSamplesOutput = 0; - mStarted = true; - - return OK; -} - -status_t AMRNBDecoder::stop() { - CHECK(mStarted); - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - delete mBufferGroup; - mBufferGroup = NULL; - - GSMDecodeFrameExit(&mState); - - mSource->stop(); - - mStarted = false; - - return OK; -} - -sp<MetaData> AMRNBDecoder::getFormat() { - sp<MetaData> srcFormat = mSource->getFormat(); - - int32_t numChannels; - int32_t sampleRate; - - CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels)); - CHECK_EQ(numChannels, 1); - - CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate)); - CHECK_EQ(sampleRate, kSampleRate); - - sp<MetaData> meta = new MetaData; - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); - meta->setInt32(kKeyChannelCount, numChannels); - meta->setInt32(kKeySampleRate, sampleRate); - - int64_t durationUs; - if (srcFormat->findInt64(kKeyDuration, &durationUs)) { - meta->setInt64(kKeyDuration, durationUs); - } - - meta->setCString(kKeyDecoderComponent, "AMRNBDecoder"); - - return meta; -} - -status_t AMRNBDecoder::read( - MediaBuffer **out, const ReadOptions *options) { - status_t err; - - *out = NULL; - - int64_t seekTimeUs; - ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { - CHECK(seekTimeUs >= 0); - - mNumSamplesOutput = 0; - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - } else { - seekTimeUs = -1; - } - - if (mInputBuffer == NULL) { - err = mSource->read(&mInputBuffer, options); - - if (err != OK) { - return err; - } - - int64_t timeUs; - if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { - mAnchorTimeUs = timeUs; - mNumSamplesOutput = 0; - } else { - // We must have a new timestamp after seeking. - CHECK(seekTimeUs < 0); - } - } - - MediaBuffer *buffer; - CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK); - - const uint8_t *inputPtr = - (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(); - - int32_t numBytesRead = - AMRDecode(mState, - (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f), - (UWord8 *)&inputPtr[1], - static_cast<int16_t *>(buffer->data()), - MIME_IETF); - - if (numBytesRead == -1 ) { - LOGE("PV AMR decoder AMRDecode() call failed"); - buffer->release(); - buffer = NULL; - return ERROR_MALFORMED; - } - ++numBytesRead; // Include the frame type header byte. - - buffer->set_range(0, kNumSamplesPerFrame * sizeof(int16_t)); - - if (static_cast<size_t>(numBytesRead) > mInputBuffer->range_length()) { - // This is bad, should never have happened, but did. Abort now. - - buffer->release(); - buffer = NULL; - - return ERROR_MALFORMED; - } - - mInputBuffer->set_range( - mInputBuffer->range_offset() + numBytesRead, - mInputBuffer->range_length() - numBytesRead); - - if (mInputBuffer->range_length() == 0) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - buffer->meta_data()->setInt64( - kKeyTime, - mAnchorTimeUs - + (mNumSamplesOutput * 1000000) / kSampleRate); - - mNumSamplesOutput += kNumSamplesPerFrame; - - *out = buffer; - - return OK; -} - -} // namespace android diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk index 5862abc..23a22ef 100644 --- a/media/libstagefright/codecs/amrnb/dec/Android.mk +++ b/media/libstagefright/codecs/amrnb/dec/Android.mk @@ -2,7 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - AMRNBDecoder.cpp \ src/a_refl.cpp \ src/agc.cpp \ src/amrdecode.cpp \ diff --git a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp b/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp deleted file mode 100644 index 5b111ef..0000000 --- a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "AMRWBDecoder.h" - -#include "pvamrwbdecoder.h" - -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MetaData.h> - -namespace android { - -static const int32_t kNumSamplesPerFrame = 320; -static const int32_t kSampleRate = 16000; - -AMRWBDecoder::AMRWBDecoder(const sp<MediaSource> &source) - : mSource(source), - mStarted(false), - mBufferGroup(NULL), - mState(NULL), - mDecoderBuf(NULL), - mDecoderCookie(NULL), - mAnchorTimeUs(0), - mNumSamplesOutput(0), - mInputBuffer(NULL) { -} - -AMRWBDecoder::~AMRWBDecoder() { - if (mStarted) { - stop(); - } -} - -status_t AMRWBDecoder::start(MetaData *params) { - CHECK(!mStarted); - - mBufferGroup = new MediaBufferGroup; - mBufferGroup->add_buffer( - new MediaBuffer(kNumSamplesPerFrame * sizeof(int16_t))); - - int32_t memReq = pvDecoder_AmrWbMemRequirements(); - mDecoderBuf = malloc(memReq); - - pvDecoder_AmrWb_Init(&mState, mDecoderBuf, &mDecoderCookie); - - mSource->start(); - - mAnchorTimeUs = 0; - mNumSamplesOutput = 0; - mStarted = true; - - return OK; -} - -status_t AMRWBDecoder::stop() { - CHECK(mStarted); - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - delete mBufferGroup; - mBufferGroup = NULL; - - free(mDecoderBuf); - mDecoderBuf = NULL; - - mSource->stop(); - - mStarted = false; - - return OK; -} - -sp<MetaData> AMRWBDecoder::getFormat() { - sp<MetaData> srcFormat = mSource->getFormat(); - - int32_t numChannels; - int32_t sampleRate; - - CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels)); - CHECK_EQ(numChannels, 1); - - CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate)); - CHECK_EQ(sampleRate, kSampleRate); - - sp<MetaData> meta = new MetaData; - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); - meta->setInt32(kKeyChannelCount, numChannels); - meta->setInt32(kKeySampleRate, sampleRate); - - int64_t durationUs; - if (srcFormat->findInt64(kKeyDuration, &durationUs)) { - meta->setInt64(kKeyDuration, durationUs); - } - - meta->setCString(kKeyDecoderComponent, "AMRWBDecoder"); - - return meta; -} - -static size_t getFrameSize(unsigned FT) { - static const size_t kFrameSizeWB[9] = { - 132, 177, 253, 285, 317, 365, 397, 461, 477 - }; - - size_t frameSize = kFrameSizeWB[FT]; - - // Round up bits to bytes and add 1 for the header byte. - frameSize = (frameSize + 7) / 8 + 1; - - return frameSize; -} - -status_t AMRWBDecoder::read( - MediaBuffer **out, const ReadOptions *options) { - status_t err; - - *out = NULL; - - int64_t seekTimeUs; - ReadOptions::SeekMode seekMode; - if (options && options->getSeekTo(&seekTimeUs, &seekMode)) { - CHECK(seekTimeUs >= 0); - - mNumSamplesOutput = 0; - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - } else { - seekTimeUs = -1; - } - - if (mInputBuffer == NULL) { - err = mSource->read(&mInputBuffer, options); - - if (err != OK) { - return err; - } - - int64_t timeUs; - if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { - mAnchorTimeUs = timeUs; - mNumSamplesOutput = 0; - } else { - // We must have a new timestamp after seeking. - CHECK(seekTimeUs < 0); - } - } - - MediaBuffer *buffer; - CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK); - - const uint8_t *inputPtr = - (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(); - - int16 mode = ((inputPtr[0] >> 3) & 0x0f); - size_t frameSize = getFrameSize(mode); - CHECK(mInputBuffer->range_length() >= frameSize); - - int16 frameType; - RX_State_wb rx_state; - mime_unsorting( - const_cast<uint8_t *>(&inputPtr[1]), - mInputSampleBuffer, - &frameType, &mode, 1, &rx_state); - - int16_t *outPtr = (int16_t *)buffer->data(); - - int16_t numSamplesOutput; - pvDecoder_AmrWb( - mode, mInputSampleBuffer, - outPtr, - &numSamplesOutput, - mDecoderBuf, frameType, mDecoderCookie); - - CHECK_EQ(numSamplesOutput, kNumSamplesPerFrame); - - for (int i = 0; i < kNumSamplesPerFrame; ++i) { - /* Delete the 2 LSBs (14-bit output) */ - outPtr[i] &= 0xfffC; - } - - buffer->set_range(0, numSamplesOutput * sizeof(int16_t)); - - mInputBuffer->set_range( - mInputBuffer->range_offset() + frameSize, - mInputBuffer->range_length() - frameSize); - - if (mInputBuffer->range_length() == 0) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - buffer->meta_data()->setInt64( - kKeyTime, - mAnchorTimeUs - + (mNumSamplesOutput * 1000000) / kSampleRate); - - mNumSamplesOutput += kNumSamplesPerFrame; - - *out = buffer; - - return OK; -} - -} // namespace android diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk index ab591d7..c9e1c25 100644 --- a/media/libstagefright/codecs/amrwb/Android.mk +++ b/media/libstagefright/codecs/amrwb/Android.mk @@ -2,7 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - AMRWBDecoder.cpp \ src/agc2_amr_wb.cpp \ src/band_pass_6k_7k.cpp \ src/dec_acelp_2p_in_64.cpp \ diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp deleted file mode 100644 index 490129f..0000000 --- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp +++ /dev/null @@ -1,622 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "AVCDecoder" -#include <utils/Log.h> - -#include "AVCDecoder.h" - -#include "avcdec_api.h" -#include "avcdec_int.h" - -#include <OMX_Component.h> - -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/Utils.h> -#include <media/stagefright/foundation/hexdump.h> - -namespace android { - -static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 }; - -static int32_t Malloc(void *userData, int32_t size, int32_t attrs) { - return reinterpret_cast<int32_t>(malloc(size)); -} - -static void Free(void *userData, int32_t ptr) { - free(reinterpret_cast<void *>(ptr)); -} - -AVCDecoder::AVCDecoder(const sp<MediaSource> &source) - : mSource(source), - mStarted(false), - mHandle(new tagAVCHandle), - mInputBuffer(NULL), - mAnchorTimeUs(0), - mNumSamplesOutput(0), - mPendingSeekTimeUs(-1), - mPendingSeekMode(MediaSource::ReadOptions::SEEK_CLOSEST_SYNC), - mTargetTimeUs(-1), - mSPSSeen(false), - mPPSSeen(false) { - memset(mHandle, 0, sizeof(tagAVCHandle)); - mHandle->AVCObject = NULL; - mHandle->userData = this; - mHandle->CBAVC_DPBAlloc = ActivateSPSWrapper; - mHandle->CBAVC_FrameBind = BindFrameWrapper; - mHandle->CBAVC_FrameUnbind = UnbindFrame; - mHandle->CBAVC_Malloc = Malloc; - mHandle->CBAVC_Free = Free; - - mFormat = new MetaData; - mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); - int32_t width, height; - CHECK(mSource->getFormat()->findInt32(kKeyWidth, &width)); - CHECK(mSource->getFormat()->findInt32(kKeyHeight, &height)); - mFormat->setInt32(kKeyWidth, width); - mFormat->setInt32(kKeyHeight, height); - mFormat->setRect(kKeyCropRect, 0, 0, width - 1, height - 1); - mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar); - mFormat->setCString(kKeyDecoderComponent, "AVCDecoder"); - - int64_t durationUs; - if (mSource->getFormat()->findInt64(kKeyDuration, &durationUs)) { - mFormat->setInt64(kKeyDuration, durationUs); - } -} - -AVCDecoder::~AVCDecoder() { - if (mStarted) { - stop(); - } - - PVAVCCleanUpDecoder(mHandle); - - delete mHandle; - mHandle = NULL; -} - -status_t AVCDecoder::start(MetaData *) { - CHECK(!mStarted); - - uint32_t type; - const void *data; - size_t size; - sp<MetaData> meta = mSource->getFormat(); - if (meta->findData(kKeyAVCC, &type, &data, &size)) { - // Parse the AVCDecoderConfigurationRecord - - const uint8_t *ptr = (const uint8_t *)data; - - CHECK(size >= 7); - CHECK_EQ(ptr[0], 1); // configurationVersion == 1 - uint8_t profile = ptr[1]; - uint8_t level = ptr[3]; - - // There is decodable content out there that fails the following - // assertion, let's be lenient for now... - // CHECK((ptr[4] >> 2) == 0x3f); // reserved - - size_t lengthSize = 1 + (ptr[4] & 3); - - // commented out check below as H264_QVGA_500_NO_AUDIO.3gp - // violates it... - // CHECK((ptr[5] >> 5) == 7); // reserved - - size_t numSeqParameterSets = ptr[5] & 31; - - ptr += 6; - size -= 6; - - for (size_t i = 0; i < numSeqParameterSets; ++i) { - CHECK(size >= 2); - size_t length = U16_AT(ptr); - - ptr += 2; - size -= 2; - - CHECK(size >= length); - - addCodecSpecificData(ptr, length); - - ptr += length; - size -= length; - } - - CHECK(size >= 1); - size_t numPictureParameterSets = *ptr; - ++ptr; - --size; - - for (size_t i = 0; i < numPictureParameterSets; ++i) { - CHECK(size >= 2); - size_t length = U16_AT(ptr); - - ptr += 2; - size -= 2; - - CHECK(size >= length); - - addCodecSpecificData(ptr, length); - - ptr += length; - size -= length; - } - } - - mSource->start(); - - mAnchorTimeUs = 0; - mNumSamplesOutput = 0; - mPendingSeekTimeUs = -1; - mPendingSeekMode = ReadOptions::SEEK_CLOSEST_SYNC; - mTargetTimeUs = -1; - mSPSSeen = false; - mPPSSeen = false; - mStarted = true; - - return OK; -} - -void AVCDecoder::addCodecSpecificData(const uint8_t *data, size_t size) { - MediaBuffer *buffer = new MediaBuffer(size + 4); - memcpy(buffer->data(), kStartCode, 4); - memcpy((uint8_t *)buffer->data() + 4, data, size); - buffer->set_range(0, size + 4); - - mCodecSpecificData.push(buffer); -} - -status_t AVCDecoder::stop() { - CHECK(mStarted); - - for (size_t i = 0; i < mCodecSpecificData.size(); ++i) { - (*mCodecSpecificData.editItemAt(i)).release(); - } - mCodecSpecificData.clear(); - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - mSource->stop(); - - releaseFrames(); - - mStarted = false; - - return OK; -} - -sp<MetaData> AVCDecoder::getFormat() { - return mFormat; -} - -static void findNALFragment( - const MediaBuffer *buffer, const uint8_t **fragPtr, size_t *fragSize) { - const uint8_t *data = - (const uint8_t *)buffer->data() + buffer->range_offset(); - - size_t size = buffer->range_length(); - - CHECK(size >= 4); - CHECK(!memcmp(kStartCode, data, 4)); - - size_t offset = 4; - while (offset + 3 < size && memcmp(kStartCode, &data[offset], 4)) { - ++offset; - } - - *fragPtr = &data[4]; - if (offset + 3 >= size) { - *fragSize = size - 4; - } else { - *fragSize = offset - 4; - } -} - -MediaBuffer *AVCDecoder::drainOutputBuffer() { - int32_t index; - int32_t Release; - AVCFrameIO Output; - Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL; - AVCDec_Status status = PVAVCDecGetOutput(mHandle, &index, &Release, &Output); - - if (status != AVCDEC_SUCCESS) { - LOGV("PVAVCDecGetOutput returned error %d", status); - return NULL; - } - - CHECK(index >= 0); - CHECK(index < (int32_t)mFrames.size()); - - MediaBuffer *mbuf = mFrames.editItemAt(index); - - bool skipFrame = false; - - if (mTargetTimeUs >= 0) { - int64_t timeUs; - CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); - CHECK(timeUs <= mTargetTimeUs); - - if (timeUs < mTargetTimeUs) { - // We're still waiting for the frame with the matching - // timestamp and we won't return the current one. - skipFrame = true; - - LOGV("skipping frame at %lld us", timeUs); - } else { - LOGV("found target frame at %lld us", timeUs); - - mTargetTimeUs = -1; - } - } - - if (!skipFrame) { - mbuf->set_range(0, mbuf->size()); - mbuf->add_ref(); - - return mbuf; - } - - return new MediaBuffer(0); -} - -status_t AVCDecoder::read( - MediaBuffer **out, const ReadOptions *options) { - *out = NULL; - - int64_t seekTimeUs; - ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { - LOGV("seek requested to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6); - - CHECK(seekTimeUs >= 0); - mPendingSeekTimeUs = seekTimeUs; - mPendingSeekMode = mode; - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - PVAVCDecReset(mHandle); - } - - if (mInputBuffer == NULL) { - LOGV("fetching new input buffer."); - - bool seeking = false; - - if (!mCodecSpecificData.isEmpty()) { - mInputBuffer = mCodecSpecificData.editItemAt(0); - mCodecSpecificData.removeAt(0); - } else { - for (;;) { - if (mPendingSeekTimeUs >= 0) { - LOGV("reading data from timestamp %lld (%.2f secs)", - mPendingSeekTimeUs, mPendingSeekTimeUs / 1E6); - } - - ReadOptions seekOptions; - if (mPendingSeekTimeUs >= 0) { - seeking = true; - - seekOptions.setSeekTo(mPendingSeekTimeUs, mPendingSeekMode); - mPendingSeekTimeUs = -1; - } - status_t err = mSource->read(&mInputBuffer, &seekOptions); - seekOptions.clearSeekTo(); - - if (err != OK) { - *out = drainOutputBuffer(); - return (*out == NULL) ? err : (status_t)OK; - } - - if (mInputBuffer->range_length() > 0) { - break; - } - - mInputBuffer->release(); - mInputBuffer = NULL; - } - } - - if (seeking) { - int64_t targetTimeUs; - if (mInputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs) - && targetTimeUs >= 0) { - mTargetTimeUs = targetTimeUs; - } else { - mTargetTimeUs = -1; - } - } - } - - const uint8_t *fragPtr; - size_t fragSize; - findNALFragment(mInputBuffer, &fragPtr, &fragSize); - - bool releaseFragment = true; - status_t err = UNKNOWN_ERROR; - - int nalType; - int nalRefIdc; - AVCDec_Status res = - PVAVCDecGetNALType( - const_cast<uint8_t *>(fragPtr), fragSize, - &nalType, &nalRefIdc); - - if (res != AVCDEC_SUCCESS) { - LOGV("cannot determine nal type"); - } else if (nalType == AVC_NALTYPE_SPS || nalType == AVC_NALTYPE_PPS - || (mSPSSeen && mPPSSeen)) { - switch (nalType) { - case AVC_NALTYPE_SPS: - { - mSPSSeen = true; - - res = PVAVCDecSeqParamSet( - mHandle, const_cast<uint8_t *>(fragPtr), - fragSize); - - if (res != AVCDEC_SUCCESS) { - LOGV("PVAVCDecSeqParamSet returned error %d", res); - break; - } - - AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject; - - int32_t width = - (pDecVid->seqParams[0]->pic_width_in_mbs_minus1 + 1) * 16; - - int32_t height = - (pDecVid->seqParams[0]->pic_height_in_map_units_minus1 + 1) * 16; - - int32_t crop_left, crop_right, crop_top, crop_bottom; - if (pDecVid->seqParams[0]->frame_cropping_flag) - { - crop_left = 2 * pDecVid->seqParams[0]->frame_crop_left_offset; - crop_right = - width - (2 * pDecVid->seqParams[0]->frame_crop_right_offset + 1); - - if (pDecVid->seqParams[0]->frame_mbs_only_flag) - { - crop_top = 2 * pDecVid->seqParams[0]->frame_crop_top_offset; - crop_bottom = - height - - (2 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1); - } - else - { - crop_top = 4 * pDecVid->seqParams[0]->frame_crop_top_offset; - crop_bottom = - height - - (4 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1); - } - } else { - crop_bottom = height - 1; - crop_right = width - 1; - crop_top = crop_left = 0; - } - - int32_t prevCropLeft, prevCropTop; - int32_t prevCropRight, prevCropBottom; - if (!mFormat->findRect( - kKeyCropRect, - &prevCropLeft, &prevCropTop, - &prevCropRight, &prevCropBottom)) { - prevCropLeft = prevCropTop = 0; - prevCropRight = width - 1; - prevCropBottom = height - 1; - } - - int32_t oldWidth, oldHeight; - CHECK(mFormat->findInt32(kKeyWidth, &oldWidth)); - CHECK(mFormat->findInt32(kKeyHeight, &oldHeight)); - - if (oldWidth != width || oldHeight != height - || prevCropLeft != crop_left - || prevCropTop != crop_top - || prevCropRight != crop_right - || prevCropBottom != crop_bottom) { - mFormat->setRect( - kKeyCropRect, - crop_left, crop_top, crop_right, crop_bottom); - - mFormat->setInt32(kKeyWidth, width); - mFormat->setInt32(kKeyHeight, height); - - err = INFO_FORMAT_CHANGED; - } else { - *out = new MediaBuffer(0); - err = OK; - } - break; - } - - case AVC_NALTYPE_PPS: - { - mPPSSeen = true; - - res = PVAVCDecPicParamSet( - mHandle, const_cast<uint8_t *>(fragPtr), - fragSize); - - if (res != AVCDEC_SUCCESS) { - LOGV("PVAVCDecPicParamSet returned error %d", res); - break; - } - - *out = new MediaBuffer(0); - - err = OK; - break; - } - - case AVC_NALTYPE_SLICE: - case AVC_NALTYPE_IDR: - { - res = PVAVCDecodeSlice( - mHandle, const_cast<uint8_t *>(fragPtr), - fragSize); - - if (res == AVCDEC_PICTURE_OUTPUT_READY) { - MediaBuffer *mbuf = drainOutputBuffer(); - if (mbuf == NULL) { - break; - } - - *out = mbuf; - - // Do _not_ release input buffer yet. - - releaseFragment = false; - err = OK; - break; - } - - if (res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS) { - *out = new MediaBuffer(0); - - err = OK; - } else { - LOGV("PVAVCDecodeSlice returned error %d", res); - } - break; - } - - case AVC_NALTYPE_SEI: - { - res = PVAVCDecSEI( - mHandle, const_cast<uint8_t *>(fragPtr), - fragSize); - - if (res != AVCDEC_SUCCESS) { - break; - } - - *out = new MediaBuffer(0); - - err = OK; - break; - } - - case AVC_NALTYPE_AUD: - case AVC_NALTYPE_FILL: - case AVC_NALTYPE_EOSEQ: - { - *out = new MediaBuffer(0); - - err = OK; - break; - } - - default: - { - LOGE("Should not be here, unknown nalType %d", nalType); - - err = ERROR_MALFORMED; - break; - } - } - } else { - // We haven't seen SPS or PPS yet. - - *out = new MediaBuffer(0); - err = OK; - } - - if (releaseFragment) { - size_t offset = mInputBuffer->range_offset(); - if (fragSize + 4 == mInputBuffer->range_length()) { - mInputBuffer->release(); - mInputBuffer = NULL; - } else { - mInputBuffer->set_range( - offset + fragSize + 4, - mInputBuffer->range_length() - fragSize - 4); - } - } - - return err; -} - -// static -int32_t AVCDecoder::ActivateSPSWrapper( - void *userData, unsigned int sizeInMbs, unsigned int numBuffers) { - return static_cast<AVCDecoder *>(userData)->activateSPS(sizeInMbs, numBuffers); -} - -// static -int32_t AVCDecoder::BindFrameWrapper( - void *userData, int32_t index, uint8_t **yuv) { - return static_cast<AVCDecoder *>(userData)->bindFrame(index, yuv); -} - -// static -void AVCDecoder::UnbindFrame(void *userData, int32_t index) { -} - -int32_t AVCDecoder::activateSPS( - unsigned int sizeInMbs, unsigned int numBuffers) { - CHECK(mFrames.isEmpty()); - - size_t frameSize = (sizeInMbs << 7) * 3; - for (unsigned int i = 0; i < numBuffers; ++i) { - MediaBuffer *buffer = new MediaBuffer(frameSize); - buffer->setObserver(this); - - mFrames.push(buffer); - } - - return 1; -} - -int32_t AVCDecoder::bindFrame(int32_t index, uint8_t **yuv) { - CHECK(index >= 0); - CHECK(index < (int32_t)mFrames.size()); - - CHECK(mInputBuffer != NULL); - int64_t timeUs; - CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); - mFrames[index]->meta_data()->setInt64(kKeyTime, timeUs); - - *yuv = (uint8_t *)mFrames[index]->data(); - - return 1; -} - -void AVCDecoder::releaseFrames() { - for (size_t i = 0; i < mFrames.size(); ++i) { - MediaBuffer *buffer = mFrames.editItemAt(i); - - buffer->setObserver(NULL); - buffer->release(); - } - mFrames.clear(); -} - -void AVCDecoder::signalBufferReturned(MediaBuffer *buffer) { -} - -} // namespace android diff --git a/media/libstagefright/codecs/avc/dec/Android.mk b/media/libstagefright/codecs/avc/dec/Android.mk index 4d4533b..2949a04 100644 --- a/media/libstagefright/codecs/avc/dec/Android.mk +++ b/media/libstagefright/codecs/avc/dec/Android.mk @@ -2,7 +2,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - AVCDecoder.cpp \ src/avcdec_api.cpp \ src/avc_bitstream.cpp \ src/header.cpp \ diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk index 6e98559..6692533 100644 --- a/media/libstagefright/codecs/g711/dec/Android.mk +++ b/media/libstagefright/codecs/g711/dec/Android.mk @@ -2,20 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - G711Decoder.cpp - -LOCAL_C_INCLUDES := \ - frameworks/base/media/libstagefright/include \ - -LOCAL_MODULE := libstagefright_g711dec - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ SoftG711.cpp LOCAL_C_INCLUDES := \ diff --git a/media/libstagefright/codecs/g711/dec/G711Decoder.cpp b/media/libstagefright/codecs/g711/dec/G711Decoder.cpp deleted file mode 100644 index 4414e4e..0000000 --- a/media/libstagefright/codecs/g711/dec/G711Decoder.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "G711Decoder" -#include <utils/Log.h> - -#include "G711Decoder.h" - -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MetaData.h> - -static const size_t kMaxNumSamplesPerFrame = 16384; - -namespace android { - -G711Decoder::G711Decoder(const sp<MediaSource> &source) - : mSource(source), - mStarted(false), - mBufferGroup(NULL) { -} - -G711Decoder::~G711Decoder() { - if (mStarted) { - stop(); - } -} - -status_t G711Decoder::start(MetaData *params) { - CHECK(!mStarted); - - const char *mime; - CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); - - mIsMLaw = false; - if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_MLAW)) { - mIsMLaw = true; - } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_ALAW)) { - return ERROR_UNSUPPORTED; - } - - mBufferGroup = new MediaBufferGroup; - mBufferGroup->add_buffer( - new MediaBuffer(kMaxNumSamplesPerFrame * sizeof(int16_t))); - - mSource->start(); - - mStarted = true; - - return OK; -} - -status_t G711Decoder::stop() { - CHECK(mStarted); - - delete mBufferGroup; - mBufferGroup = NULL; - - mSource->stop(); - - mStarted = false; - - return OK; -} - -sp<MetaData> G711Decoder::getFormat() { - sp<MetaData> srcFormat = mSource->getFormat(); - - int32_t numChannels; - int32_t sampleRate; - - CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels)); - CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate)); - - sp<MetaData> meta = new MetaData; - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); - meta->setInt32(kKeyChannelCount, numChannels); - meta->setInt32(kKeySampleRate, sampleRate); - - int64_t durationUs; - if (srcFormat->findInt64(kKeyDuration, &durationUs)) { - meta->setInt64(kKeyDuration, durationUs); - } - - meta->setCString(kKeyDecoderComponent, "G711Decoder"); - - return meta; -} - -status_t G711Decoder::read( - MediaBuffer **out, const ReadOptions *options) { - status_t err; - - *out = NULL; - - int64_t seekTimeUs; - ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { - CHECK(seekTimeUs >= 0); - } else { - seekTimeUs = -1; - } - - MediaBuffer *inBuffer; - err = mSource->read(&inBuffer, options); - - if (err != OK) { - return err; - } - - if (inBuffer->range_length() > kMaxNumSamplesPerFrame) { - LOGE("input buffer too large (%d).", inBuffer->range_length()); - - inBuffer->release(); - inBuffer = NULL; - - return ERROR_UNSUPPORTED; - } - - int64_t timeUs; - CHECK(inBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); - - const uint8_t *inputPtr = - (const uint8_t *)inBuffer->data() + inBuffer->range_offset(); - - MediaBuffer *outBuffer; - CHECK_EQ(mBufferGroup->acquire_buffer(&outBuffer), OK); - - if (mIsMLaw) { - DecodeMLaw( - static_cast<int16_t *>(outBuffer->data()), - inputPtr, inBuffer->range_length()); - } else { - DecodeALaw( - static_cast<int16_t *>(outBuffer->data()), - inputPtr, inBuffer->range_length()); - } - - // Each 8-bit byte is converted into a 16-bit sample. - outBuffer->set_range(0, inBuffer->range_length() * 2); - - outBuffer->meta_data()->setInt64(kKeyTime, timeUs); - - inBuffer->release(); - inBuffer = NULL; - - *out = outBuffer; - - return OK; -} - -// static -void G711Decoder::DecodeALaw( - int16_t *out, const uint8_t *in, size_t inSize) { - while (inSize-- > 0) { - int32_t x = *in++; - - int32_t ix = x ^ 0x55; - ix &= 0x7f; - - int32_t iexp = ix >> 4; - int32_t mant = ix & 0x0f; - - if (iexp > 0) { - mant += 16; - } - - mant = (mant << 4) + 8; - - if (iexp > 1) { - mant = mant << (iexp - 1); - } - - *out++ = (x > 127) ? mant : -mant; - } -} - -// static -void G711Decoder::DecodeMLaw( - int16_t *out, const uint8_t *in, size_t inSize) { - while (inSize-- > 0) { - int32_t x = *in++; - - int32_t mantissa = ~x; - int32_t exponent = (mantissa >> 4) & 7; - int32_t segment = exponent + 1; - mantissa &= 0x0f; - - int32_t step = 4 << segment; - - int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33; - - *out++ = (x < 0x80) ? -abs : abs; - } -} - -} // namespace android diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk index f1bec08..2ffa5f2 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk +++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk @@ -2,7 +2,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - M4vH263Decoder.cpp \ src/adaptive_smooth_no_mmx.cpp \ src/bitstream.cpp \ src/block_idct.cpp \ diff --git a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp deleted file mode 100644 index 2bdb3ef..0000000 --- a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -//#define LOG_NDEBUG 0 -#define LOG_TAG "M4vH263Decoder" -#include <utils/Log.h> -#include <stdlib.h> // for free -#include "ESDS.h" -#include "M4vH263Decoder.h" - -#include "mp4dec_api.h" - -#include <OMX_Component.h> -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/Utils.h> - -namespace android { - -M4vH263Decoder::M4vH263Decoder(const sp<MediaSource> &source) - : mSource(source), - mStarted(false), - mHandle(new tagvideoDecControls), - mInputBuffer(NULL), - mNumSamplesOutput(0), - mTargetTimeUs(-1) { - - LOGV("M4vH263Decoder"); - memset(mHandle, 0, sizeof(tagvideoDecControls)); - mFormat = new MetaData; - mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); - - // CHECK(mSource->getFormat()->findInt32(kKeyWidth, &mWidth)); - // CHECK(mSource->getFormat()->findInt32(kKeyHeight, &mHeight)); - - // We'll ignore the dimension advertised by the source, the decoder - // appears to require us to always start with the default dimensions - // of 352 x 288 to operate correctly and later react to changes in - // the dimensions as needed. - mWidth = 352; - mHeight = 288; - - mFormat->setInt32(kKeyWidth, mWidth); - mFormat->setInt32(kKeyHeight, mHeight); - mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar); - mFormat->setCString(kKeyDecoderComponent, "M4vH263Decoder"); -} - -M4vH263Decoder::~M4vH263Decoder() { - if (mStarted) { - stop(); - } - - delete mHandle; - mHandle = NULL; -} - -void M4vH263Decoder::allocateFrames(int32_t width, int32_t height) { - size_t frameSize = - (((width + 15) & - 16) * ((height + 15) & - 16) * 3) / 2; - - for (uint32_t i = 0; i < 2; ++i) { - mFrames[i] = new MediaBuffer(frameSize); - mFrames[i]->setObserver(this); - } - - PVSetReferenceYUV( - mHandle, - (uint8_t *)mFrames[1]->data()); -} - -status_t M4vH263Decoder::start(MetaData *) { - CHECK(!mStarted); - - const char *mime = NULL; - sp<MetaData> meta = mSource->getFormat(); - CHECK(meta->findCString(kKeyMIMEType, &mime)); - - MP4DecodingMode mode; - if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { - mode = MPEG4_MODE; - } else { - CHECK(!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)); - mode = H263_MODE; - } - - uint32_t type; - const void *data = NULL; - size_t size = 0; - uint8_t *vol_data[1] = {0}; - int32_t vol_size = 0; - if (meta->findData(kKeyESDS, &type, &data, &size)) { - ESDS esds((const uint8_t *)data, size); - CHECK_EQ(esds.InitCheck(), (status_t)OK); - - const void *codec_specific_data; - size_t codec_specific_data_size; - esds.getCodecSpecificInfo( - &codec_specific_data, &codec_specific_data_size); - - vol_data[0] = (uint8_t *) malloc(codec_specific_data_size); - memcpy(vol_data[0], codec_specific_data, codec_specific_data_size); - vol_size = codec_specific_data_size; - } else { - vol_data[0] = NULL; - vol_size = 0; - - } - - Bool success = PVInitVideoDecoder( - mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode); - if (vol_data[0]) free(vol_data[0]); - - if (success != PV_TRUE) { - LOGW("PVInitVideoDecoder failed. Unsupported content?"); - return ERROR_UNSUPPORTED; - } - - MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle); - if (mode != actualMode) { - PVCleanUpVideoDecoder(mHandle); - return UNKNOWN_ERROR; - } - - PVSetPostProcType((VideoDecControls *) mHandle, 0); - - int32_t width, height; - PVGetVideoDimensions(mHandle, &width, &height); - if (mode == H263_MODE && (width == 0 || height == 0)) { - width = 352; - height = 288; - } - allocateFrames(width, height); - - mSource->start(); - - mNumSamplesOutput = 0; - mTargetTimeUs = -1; - mStarted = true; - - return OK; -} - -status_t M4vH263Decoder::stop() { - CHECK(mStarted); - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - mSource->stop(); - - releaseFrames(); - - mStarted = false; - return (PVCleanUpVideoDecoder(mHandle) == PV_TRUE)? OK: UNKNOWN_ERROR; -} - -sp<MetaData> M4vH263Decoder::getFormat() { - return mFormat; -} - -status_t M4vH263Decoder::read( - MediaBuffer **out, const ReadOptions *options) { - *out = NULL; - - bool seeking = false; - int64_t seekTimeUs; - ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { - seeking = true; - CHECK_EQ((int)PVResetVideoDecoder(mHandle), PV_TRUE); - } - - MediaBuffer *inputBuffer = NULL; - status_t err = mSource->read(&inputBuffer, options); - if (err != OK) { - return err; - } - - if (seeking) { - int64_t targetTimeUs; - if (inputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs) - && targetTimeUs >= 0) { - mTargetTimeUs = targetTimeUs; - } else { - mTargetTimeUs = -1; - } - } - - uint8_t *bitstream = - (uint8_t *) inputBuffer->data() + inputBuffer->range_offset(); - - uint32_t timestamp = 0xFFFFFFFF; - int32_t bufferSize = inputBuffer->range_length(); - uint32_t useExtTimestamp = 0; - if (PVDecodeVideoFrame( - mHandle, &bitstream, ×tamp, &bufferSize, - &useExtTimestamp, - (uint8_t *)mFrames[mNumSamplesOutput & 0x01]->data()) - != PV_TRUE) { - LOGE("failed to decode video frame."); - - inputBuffer->release(); - inputBuffer = NULL; - - return UNKNOWN_ERROR; - } - - int32_t disp_width, disp_height; - PVGetVideoDimensions(mHandle, &disp_width, &disp_height); - - int32_t buf_width, buf_height; - PVGetBufferDimensions(mHandle, &buf_width, &buf_height); - - if (buf_width != mWidth || buf_height != mHeight) { - ++mNumSamplesOutput; // The client will never get to see this frame. - - inputBuffer->release(); - inputBuffer = NULL; - - mWidth = buf_width; - mHeight = buf_height; - mFormat->setInt32(kKeyWidth, mWidth); - mFormat->setInt32(kKeyHeight, mHeight); - - CHECK_LE(disp_width, buf_width); - CHECK_LE(disp_height, buf_height); - - mFormat->setRect(kKeyCropRect, 0, 0, disp_width - 1, disp_height - 1); - - return INFO_FORMAT_CHANGED; - } - - int64_t timeUs; - CHECK(inputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); - - inputBuffer->release(); - inputBuffer = NULL; - - bool skipFrame = false; - - if (mTargetTimeUs >= 0) { - CHECK(timeUs <= mTargetTimeUs); - - if (timeUs < mTargetTimeUs) { - // We're still waiting for the frame with the matching - // timestamp and we won't return the current one. - skipFrame = true; - - LOGV("skipping frame at %lld us", timeUs); - } else { - LOGV("found target frame at %lld us", timeUs); - - mTargetTimeUs = -1; - } - } - - if (skipFrame) { - *out = new MediaBuffer(0); - } else { - *out = mFrames[mNumSamplesOutput & 0x01]; - (*out)->add_ref(); - (*out)->meta_data()->setInt64(kKeyTime, timeUs); - } - - ++mNumSamplesOutput; - - return OK; -} - -void M4vH263Decoder::releaseFrames() { - for (size_t i = 0; i < sizeof(mFrames) / sizeof(mFrames[0]); ++i) { - MediaBuffer *buffer = mFrames[i]; - - buffer->setObserver(NULL); - buffer->release(); - - mFrames[i] = NULL; - } -} - -void M4vH263Decoder::signalBufferReturned(MediaBuffer *buffer) { - LOGV("signalBufferReturned"); -} - - -} // namespace android diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk index 229988e..a08c9f0 100644 --- a/media/libstagefright/codecs/mp3dec/Android.mk +++ b/media/libstagefright/codecs/mp3dec/Android.mk @@ -2,7 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - MP3Decoder.cpp \ src/pvmp3_normalize.cpp \ src/pvmp3_alias_reduction.cpp \ src/pvmp3_crc.cpp \ diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp deleted file mode 100644 index 0ba42ff..0000000 --- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "MP3Decoder" - -#include "MP3Decoder.h" - -#include "include/pvmp3decoder_api.h" - -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MetaData.h> - -namespace android { - -MP3Decoder::MP3Decoder(const sp<MediaSource> &source) - : mSource(source), - mNumChannels(0), - mStarted(false), - mBufferGroup(NULL), - mConfig(new tPVMP3DecoderExternal), - mDecoderBuf(NULL), - mAnchorTimeUs(0), - mNumFramesOutput(0), - mInputBuffer(NULL) { - init(); -} - -void MP3Decoder::init() { - sp<MetaData> srcFormat = mSource->getFormat(); - - int32_t sampleRate; - CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels)); - CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate)); - - mMeta = new MetaData; - mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); - mMeta->setInt32(kKeyChannelCount, mNumChannels); - mMeta->setInt32(kKeySampleRate, sampleRate); - - int64_t durationUs; - if (srcFormat->findInt64(kKeyDuration, &durationUs)) { - mMeta->setInt64(kKeyDuration, durationUs); - } - - mMeta->setCString(kKeyDecoderComponent, "MP3Decoder"); -} - -MP3Decoder::~MP3Decoder() { - if (mStarted) { - stop(); - } - - delete mConfig; - mConfig = NULL; -} - -status_t MP3Decoder::start(MetaData *params) { - CHECK(!mStarted); - - mBufferGroup = new MediaBufferGroup; - mBufferGroup->add_buffer(new MediaBuffer(4608 * 2)); - - mConfig->equalizerType = flat; - mConfig->crcEnabled = false; - - uint32_t memRequirements = pvmp3_decoderMemRequirements(); - mDecoderBuf = malloc(memRequirements); - - pvmp3_InitDecoder(mConfig, mDecoderBuf); - - mSource->start(); - - mAnchorTimeUs = 0; - mNumFramesOutput = 0; - mStarted = true; - - return OK; -} - -status_t MP3Decoder::stop() { - CHECK(mStarted); - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - free(mDecoderBuf); - mDecoderBuf = NULL; - - delete mBufferGroup; - mBufferGroup = NULL; - - mSource->stop(); - - mStarted = false; - - return OK; -} - -sp<MetaData> MP3Decoder::getFormat() { - return mMeta; -} - -status_t MP3Decoder::read( - MediaBuffer **out, const ReadOptions *options) { - status_t err; - - *out = NULL; - - int64_t seekTimeUs; - ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { - CHECK(seekTimeUs >= 0); - - mNumFramesOutput = 0; - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - // Make sure that the next buffer output does not still - // depend on fragments from the last one decoded. - pvmp3_InitDecoder(mConfig, mDecoderBuf); - } else { - seekTimeUs = -1; - } - - if (mInputBuffer == NULL) { - err = mSource->read(&mInputBuffer, options); - - if (err != OK) { - return err; - } - - int64_t timeUs; - if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { - mAnchorTimeUs = timeUs; - mNumFramesOutput = 0; - } else { - // We must have a new timestamp after seeking. - CHECK(seekTimeUs < 0); - } - } - - MediaBuffer *buffer; - CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK); - - mConfig->pInputBuffer = - (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(); - - mConfig->inputBufferCurrentLength = mInputBuffer->range_length(); - mConfig->inputBufferMaxLength = 0; - mConfig->inputBufferUsedLength = 0; - - mConfig->outputFrameSize = buffer->size() / sizeof(int16_t); - mConfig->pOutputBuffer = static_cast<int16_t *>(buffer->data()); - - ERROR_CODE decoderErr; - if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf)) - != NO_DECODING_ERROR) { - LOGV("mp3 decoder returned error %d", decoderErr); - - if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR || - mConfig->outputFrameSize == 0) { - - if (mConfig->outputFrameSize == 0) { - LOGE("Output frame size is 0"); - } - buffer->release(); - buffer = NULL; - - mInputBuffer->release(); - mInputBuffer = NULL; - - return UNKNOWN_ERROR; - } - - // This is recoverable, just ignore the current frame and - // play silence instead. - memset(buffer->data(), 0, mConfig->outputFrameSize * sizeof(int16_t)); - mConfig->inputBufferUsedLength = mInputBuffer->range_length(); - } - - buffer->set_range( - 0, mConfig->outputFrameSize * sizeof(int16_t)); - - mInputBuffer->set_range( - mInputBuffer->range_offset() + mConfig->inputBufferUsedLength, - mInputBuffer->range_length() - mConfig->inputBufferUsedLength); - - if (mInputBuffer->range_length() == 0) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - buffer->meta_data()->setInt64( - kKeyTime, - mAnchorTimeUs - + (mNumFramesOutput * 1000000) / mConfig->samplingRate); - - mNumFramesOutput += mConfig->outputFrameSize / mNumChannels; - - *out = buffer; - - return OK; -} - -} // namespace android diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk index 832b885..32bbd6b 100644 --- a/media/libstagefright/codecs/on2/dec/Android.mk +++ b/media/libstagefright/codecs/on2/dec/Android.mk @@ -2,24 +2,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - VPXDecoder.cpp \ - -LOCAL_MODULE := libstagefright_vpxdec - -LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/base/media/libstagefright/include \ - frameworks/base/include/media/stagefright/openmax \ - $(TOP)/external/libvpx \ - $(TOP)/external/libvpx/vpx_codec \ - $(TOP)/external/libvpx/vpx_ports - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ SoftVPX.cpp LOCAL_C_INCLUDES := \ @@ -30,7 +12,6 @@ LOCAL_C_INCLUDES := \ frameworks/base/include/media/stagefright/openmax \ LOCAL_STATIC_LIBRARIES := \ - libstagefright_vpxdec \ libvpx LOCAL_SHARED_LIBRARIES := \ diff --git a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp deleted file mode 100644 index 489e5ad..0000000 --- a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "VPXDecoder" -#include <utils/Log.h> - -#include "VPXDecoder.h" - -#include <OMX_Component.h> - -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/Utils.h> - -#include "vpx/vpx_decoder.h" -#include "vpx/vpx_codec.h" -#include "vpx/vp8dx.h" - -namespace android { - -VPXDecoder::VPXDecoder(const sp<MediaSource> &source) - : mSource(source), - mStarted(false), - mBufferSize(0), - mCtx(NULL), - mBufferGroup(NULL), - mTargetTimeUs(-1) { - sp<MetaData> inputFormat = source->getFormat(); - const char *mime; - CHECK(inputFormat->findCString(kKeyMIMEType, &mime)); - CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_VPX)); - - CHECK(inputFormat->findInt32(kKeyWidth, &mWidth)); - CHECK(inputFormat->findInt32(kKeyHeight, &mHeight)); - - mBufferSize = (mWidth * mHeight * 3) / 2; - - mFormat = new MetaData; - mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); - mFormat->setInt32(kKeyWidth, mWidth); - mFormat->setInt32(kKeyHeight, mHeight); - mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar); - mFormat->setCString(kKeyDecoderComponent, "VPXDecoder"); - - int64_t durationUs; - if (inputFormat->findInt64(kKeyDuration, &durationUs)) { - mFormat->setInt64(kKeyDuration, durationUs); - } -} - -VPXDecoder::~VPXDecoder() { - if (mStarted) { - stop(); - } -} - -status_t VPXDecoder::start(MetaData *) { - if (mStarted) { - return UNKNOWN_ERROR; - } - - status_t err = mSource->start(); - - if (err != OK) { - return err; - } - - mCtx = new vpx_codec_ctx_t; - vpx_codec_err_t vpx_err; - if ((vpx_err = vpx_codec_dec_init( - (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, NULL, 0))) { - LOGE("on2 decoder failed to initialize. (%d)", vpx_err); - - mSource->stop(); - - return UNKNOWN_ERROR; - } - - mBufferGroup = new MediaBufferGroup; - mBufferGroup->add_buffer(new MediaBuffer(mBufferSize)); - mBufferGroup->add_buffer(new MediaBuffer(mBufferSize)); - - mTargetTimeUs = -1; - - mStarted = true; - - return OK; -} - -status_t VPXDecoder::stop() { - if (!mStarted) { - return UNKNOWN_ERROR; - } - - delete mBufferGroup; - mBufferGroup = NULL; - - vpx_codec_destroy((vpx_codec_ctx_t *)mCtx); - delete (vpx_codec_ctx_t *)mCtx; - mCtx = NULL; - - mSource->stop(); - - mStarted = false; - - return OK; -} - -sp<MetaData> VPXDecoder::getFormat() { - return mFormat; -} - -status_t VPXDecoder::read( - MediaBuffer **out, const ReadOptions *options) { - *out = NULL; - - bool seeking = false; - int64_t seekTimeUs; - ReadOptions::SeekMode seekMode; - if (options && options->getSeekTo(&seekTimeUs, &seekMode)) { - seeking = true; - } - - MediaBuffer *input; - status_t err = mSource->read(&input, options); - - if (err != OK) { - return err; - } - - LOGV("read %d bytes from source\n", input->range_length()); - - if (seeking) { - int64_t targetTimeUs; - if (input->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs) - && targetTimeUs >= 0) { - mTargetTimeUs = targetTimeUs; - } else { - mTargetTimeUs = -1; - } - } - - if (vpx_codec_decode( - (vpx_codec_ctx_t *)mCtx, - (uint8_t *)input->data() + input->range_offset(), - input->range_length(), - NULL, - 0)) { - LOGE("on2 decoder failed to decode frame."); - input->release(); - input = NULL; - - return UNKNOWN_ERROR; - } - - LOGV("successfully decoded 1 or more frames."); - - int64_t timeUs; - CHECK(input->meta_data()->findInt64(kKeyTime, &timeUs)); - - input->release(); - input = NULL; - - bool skipFrame = false; - - if (mTargetTimeUs >= 0) { - CHECK(timeUs <= mTargetTimeUs); - - if (timeUs < mTargetTimeUs) { - // We're still waiting for the frame with the matching - // timestamp and we won't return the current one. - skipFrame = true; - - LOGV("skipping frame at %lld us", timeUs); - } else { - LOGV("found target frame at %lld us", timeUs); - - mTargetTimeUs = -1; - } - } - - if (skipFrame) { - *out = new MediaBuffer(0); - return OK; - } - - vpx_codec_iter_t iter = NULL; - vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter); - - if (img == NULL) { - // The VPX format supports "internal-only" frames that are - // referenced by future content but never actually displayed, so - // this is a perfectly valid scenario. - - *out = new MediaBuffer(0); - return OK; - } - - CHECK_EQ(img->fmt, IMG_FMT_I420); - - int32_t width = img->d_w; - int32_t height = img->d_h; - - if (width != mWidth || height != mHeight) { - LOGI("Image dimensions changed, width = %d, height = %d", - width, height); - - mWidth = width; - mHeight = height; - mFormat->setInt32(kKeyWidth, width); - mFormat->setInt32(kKeyHeight, height); - - mBufferSize = (mWidth * mHeight * 3) / 2; - delete mBufferGroup; - mBufferGroup = new MediaBufferGroup; - mBufferGroup->add_buffer(new MediaBuffer(mBufferSize)); - mBufferGroup->add_buffer(new MediaBuffer(mBufferSize)); - - return INFO_FORMAT_CHANGED; - } - - MediaBuffer *output; - CHECK_EQ(mBufferGroup->acquire_buffer(&output), OK); - - const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y]; - uint8_t *dst = (uint8_t *)output->data(); - for (size_t i = 0; i < img->d_h; ++i) { - memcpy(dst, srcLine, img->d_w); - - srcLine += img->stride[PLANE_Y]; - dst += img->d_w; - } - - srcLine = (const uint8_t *)img->planes[PLANE_U]; - for (size_t i = 0; i < img->d_h / 2; ++i) { - memcpy(dst, srcLine, img->d_w / 2); - - srcLine += img->stride[PLANE_U]; - dst += img->d_w / 2; - } - - srcLine = (const uint8_t *)img->planes[PLANE_V]; - for (size_t i = 0; i < img->d_h / 2; ++i) { - memcpy(dst, srcLine, img->d_w / 2); - - srcLine += img->stride[PLANE_V]; - dst += img->d_w / 2; - } - - output->set_range(0, (width * height * 3) / 2); - - output->meta_data()->setInt64(kKeyTime, timeUs); - - *out = output; - - return OK; -} - -} // namespace android - diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk index 9251229..f33f3ac 100644 --- a/media/libstagefright/codecs/vorbis/dec/Android.mk +++ b/media/libstagefright/codecs/vorbis/dec/Android.mk @@ -2,21 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - VorbisDecoder.cpp \ - -LOCAL_C_INCLUDES := \ - frameworks/base/media/libstagefright/include \ - external/tremolo \ - -LOCAL_MODULE := libstagefright_vorbisdec - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ SoftVorbis.cpp LOCAL_C_INCLUDES := \ @@ -24,9 +9,6 @@ LOCAL_C_INCLUDES := \ frameworks/base/media/libstagefright/include \ frameworks/base/include/media/stagefright/openmax \ -LOCAL_STATIC_LIBRARIES := \ - libstagefright_vorbisdec - LOCAL_SHARED_LIBRARIES := \ libvorbisidec libstagefright libstagefright_omx \ libstagefright_foundation libutils diff --git a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp deleted file mode 100644 index e14fb95..0000000 --- a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "VorbisDecoder" -#include <utils/Log.h> - -#include "VorbisDecoder.h" - -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MetaData.h> - -extern "C" { - #include <Tremolo/codec_internal.h> - - int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb); - int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb); - int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb); -} - -namespace android { - -VorbisDecoder::VorbisDecoder(const sp<MediaSource> &source) - : mSource(source), - mStarted(false), - mBufferGroup(NULL), - mAnchorTimeUs(0), - mNumFramesOutput(0), - mState(NULL), - mVi(NULL) { - sp<MetaData> srcFormat = mSource->getFormat(); - CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels)); - CHECK(srcFormat->findInt32(kKeySampleRate, &mSampleRate)); -} - -VorbisDecoder::~VorbisDecoder() { - if (mStarted) { - stop(); - } -} - -static void makeBitReader( - const void *data, size_t size, - ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) { - buf->data = (uint8_t *)data; - buf->size = size; - buf->refcount = 1; - buf->ptr.owner = NULL; - - ref->buffer = buf; - ref->begin = 0; - ref->length = size; - ref->next = NULL; - - oggpack_readinit(bits, ref); -} - -status_t VorbisDecoder::start(MetaData *params) { - CHECK(!mStarted); - - mBufferGroup = new MediaBufferGroup; - mBufferGroup->add_buffer( - new MediaBuffer(kMaxNumSamplesPerBuffer * sizeof(int16_t))); - - mSource->start(); - - sp<MetaData> meta = mSource->getFormat(); - - mVi = new vorbis_info; - vorbis_info_init(mVi); - - /////////////////////////////////////////////////////////////////////////// - - uint32_t type; - const void *data; - size_t size; - CHECK(meta->findData(kKeyVorbisInfo, &type, &data, &size)); - - ogg_buffer buf; - ogg_reference ref; - oggpack_buffer bits; - makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits); - CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits)); - - /////////////////////////////////////////////////////////////////////////// - - CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size)); - - makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits); - CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits)); - - /////////////////////////////////////////////////////////////////////////// - - mState = new vorbis_dsp_state; - CHECK_EQ(0, vorbis_dsp_init(mState, mVi)); - - mAnchorTimeUs = 0; - mNumFramesOutput = 0; - - // If the source never limits the number of valid frames contained - // in the input data, we'll assume that all of the decoded frames are - // valid. - mNumFramesLeftOnPage = -1; - - mStarted = true; - - return OK; -} - -status_t VorbisDecoder::stop() { - CHECK(mStarted); - - vorbis_dsp_clear(mState); - delete mState; - mState = NULL; - - vorbis_info_clear(mVi); - delete mVi; - mVi = NULL; - - delete mBufferGroup; - mBufferGroup = NULL; - - mSource->stop(); - - mStarted = false; - - return OK; -} - -sp<MetaData> VorbisDecoder::getFormat() { - sp<MetaData> srcFormat = mSource->getFormat(); - - sp<MetaData> meta = new MetaData; - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); - meta->setInt32(kKeyChannelCount, mNumChannels); - meta->setInt32(kKeySampleRate, mSampleRate); - - int64_t durationUs; - if (srcFormat->findInt64(kKeyDuration, &durationUs)) { - meta->setInt64(kKeyDuration, durationUs); - } - - meta->setCString(kKeyDecoderComponent, "VorbisDecoder"); - - return meta; -} - -int VorbisDecoder::decodePacket(MediaBuffer *packet, MediaBuffer *out) { - ogg_buffer buf; - buf.data = (uint8_t *)packet->data() + packet->range_offset(); - buf.size = packet->range_length(); - buf.refcount = 1; - buf.ptr.owner = NULL; - - ogg_reference ref; - ref.buffer = &buf; - ref.begin = 0; - ref.length = packet->range_length(); - ref.next = NULL; - - ogg_packet pack; - pack.packet = &ref; - pack.bytes = packet->range_length(); - pack.b_o_s = 0; - pack.e_o_s = 0; - pack.granulepos = 0; - pack.packetno = 0; - - int numFrames = 0; - - int err = vorbis_dsp_synthesis(mState, &pack, 1); - if (err != 0) { - LOGW("vorbis_dsp_synthesis returned %d", err); - } else { - numFrames = vorbis_dsp_pcmout( - mState, (int16_t *)out->data(), kMaxNumSamplesPerBuffer); - - if (numFrames < 0) { - LOGE("vorbis_dsp_pcmout returned %d", numFrames); - numFrames = 0; - } - } - - if (mNumFramesLeftOnPage >= 0) { - if (numFrames > mNumFramesLeftOnPage) { - LOGV("discarding %d frames at end of page", - numFrames - mNumFramesLeftOnPage); - numFrames = mNumFramesLeftOnPage; - } - mNumFramesLeftOnPage -= numFrames; - } - - out->set_range(0, numFrames * sizeof(int16_t) * mNumChannels); - - return numFrames; -} - -status_t VorbisDecoder::read( - MediaBuffer **out, const ReadOptions *options) { - status_t err; - - *out = NULL; - - int64_t seekTimeUs; - ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { - CHECK(seekTimeUs >= 0); - - mNumFramesOutput = 0; - vorbis_dsp_restart(mState); - } else { - seekTimeUs = -1; - } - - MediaBuffer *inputBuffer; - err = mSource->read(&inputBuffer, options); - - if (err != OK) { - return ERROR_END_OF_STREAM; - } - - int64_t timeUs; - if (inputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { - mAnchorTimeUs = timeUs; - mNumFramesOutput = 0; - } else { - // We must have a new timestamp after seeking. - CHECK(seekTimeUs < 0); - } - - int32_t numPageSamples; - if (inputBuffer->meta_data()->findInt32( - kKeyValidSamples, &numPageSamples)) { - CHECK(numPageSamples >= 0); - mNumFramesLeftOnPage = numPageSamples; - } - - MediaBuffer *outputBuffer; - CHECK_EQ(mBufferGroup->acquire_buffer(&outputBuffer), OK); - - int numFrames = decodePacket(inputBuffer, outputBuffer); - - inputBuffer->release(); - inputBuffer = NULL; - - outputBuffer->meta_data()->setInt64( - kKeyTime, - mAnchorTimeUs - + (mNumFramesOutput * 1000000ll) / mSampleRate); - - mNumFramesOutput += numFrames; - - *out = outputBuffer; - - return OK; -} - -} // namespace android diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h index 2e25dd9..0e9af69 100644 --- a/media/libstagefright/include/HTTPBase.h +++ b/media/libstagefright/include/HTTPBase.h @@ -53,6 +53,8 @@ struct HTTPBase : public DataSource { static sp<HTTPBase> Create(uint32_t flags = 0); + static void RegisterSocketUser(int s, uid_t uid); + protected: void addBandwidthMeasurement(size_t numBytes, int64_t delayUs); diff --git a/media/libstagefright/include/HTTPStream.h b/media/libstagefright/include/HTTPStream.h deleted file mode 100644 index 88ba9d6..0000000 --- a/media/libstagefright/include/HTTPStream.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef HTTP_STREAM_H_ - -#define HTTP_STREAM_H_ - -#include <sys/types.h> - -#include <media/stagefright/foundation/AString.h> -#include <media/stagefright/MediaErrors.h> -#include <utils/KeyedVector.h> -#include <utils/threads.h> - -namespace android { - -class HTTPStream { -public: - HTTPStream(); - ~HTTPStream(); - - void setUID(uid_t uid); - - status_t connect(const char *server, int port = -1, bool https = false); - status_t disconnect(); - - status_t send(const char *data, size_t size); - - // Assumes data is a '\0' terminated string. - status_t send(const char *data); - - // Receive up to "size" bytes of data. - ssize_t receive(void *data, size_t size); - - status_t receive_header(int *http_status); - - // The header key used to retrieve the status line. - static const char *kStatusKey; - - bool find_header_value( - const AString &key, AString *value) const; - - // Pass a negative value to disable the timeout. - void setReceiveTimeout(int seconds); - - // Receive a line of data terminated by CRLF, line will be '\0' terminated - // _excluding_ the termianting CRLF. - status_t receive_line(char *line, size_t size); - - static void RegisterSocketUser(int s, uid_t uid); - -private: - enum State { - READY, - CONNECTING, - CONNECTED - }; - - State mState; - Mutex mLock; - - bool mUIDValid; - uid_t mUID; - - int mSocket; - - KeyedVector<AString, AString> mHeaders; - - void *mSSLContext; - void *mSSL; - - HTTPStream(const HTTPStream &); - HTTPStream &operator=(const HTTPStream &); -}; - -} // namespace android - -#endif // HTTP_STREAM_H_ diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h deleted file mode 100644 index c265b3a..0000000 --- a/media/libstagefright/include/NuHTTPDataSource.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef NU_HTTP_DATA_SOURCE_H_ - -#define NU_HTTP_DATA_SOURCE_H_ - -#include <utils/List.h> -#include <utils/String8.h> -#include <utils/threads.h> - -#include "HTTPStream.h" -#include "include/HTTPBase.h" - -namespace android { - -struct NuHTTPDataSource : public HTTPBase { - NuHTTPDataSource(uint32_t flags = 0); - - virtual status_t connect( - const char *uri, - const KeyedVector<String8, String8> *headers = NULL, - off64_t offset = 0); - - virtual void disconnect(); - - virtual status_t initCheck() const; - - virtual ssize_t readAt(off64_t offset, void *data, size_t size); - virtual status_t getSize(off64_t *size); - virtual uint32_t flags(); - - virtual sp<DecryptHandle> DrmInitialization(); - virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client); - virtual String8 getUri(); - - virtual String8 getMIMEType() const; - -protected: - virtual ~NuHTTPDataSource(); - -private: - enum State { - DISCONNECTED, - CONNECTING, - CONNECTED - }; - - Mutex mLock; - - uint32_t mFlags; - - State mState; - - String8 mHost; - unsigned mPort; - String8 mPath; - bool mHTTPS; - String8 mHeaders; - String8 mUri; - - HTTPStream mHTTP; - off64_t mOffset; - off64_t mContentLength; - bool mContentLengthValid; - bool mHasChunkedTransferEncoding; - - String8 mContentType; - - // The number of data bytes in the current chunk before any subsequent - // chunk header (or -1 if no more chunks). - ssize_t mChunkDataBytesLeft; - - sp<DecryptHandle> mDecryptHandle; - DrmManagerClient *mDrmManagerClient; - - status_t connect( - const char *uri, const String8 &headers, off64_t offset); - - status_t connect( - const char *host, unsigned port, const char *path, - bool https, - const String8 &headers, - off64_t offset); - - // Read up to "size" bytes of data, respect transfer encoding. - ssize_t internalRead(void *data, size_t size); - - void applyTimeoutResponse(); - - static void MakeFullHeaders( - const KeyedVector<String8, String8> *overrides, - String8 *headers); - - NuHTTPDataSource(const NuHTTPDataSource &); - NuHTTPDataSource &operator=(const NuHTTPDataSource &); -}; - -} // namespace android - -#endif // NU_HTTP_DATA_SOURCE_H_ diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index ec3e5fa..d54b1c1 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -121,6 +121,7 @@ protected: virtual ~OMX(); private: + struct CallbackDispatcherThread; struct CallbackDispatcher; Mutex mLock; diff --git a/media/libstagefright/include/ThreadedSource.h b/media/libstagefright/include/ThreadedSource.h deleted file mode 100644 index c67295c..0000000 --- a/media/libstagefright/include/ThreadedSource.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef THREADED_SOURCE_H_ - -#define THREADED_SOURCE_H_ - -#include <media/stagefright/foundation/ABase.h> -#include <media/stagefright/foundation/AHandlerReflector.h> -#include <media/stagefright/foundation/ALooper.h> -#include <media/stagefright/MediaSource.h> -#include <utils/threads.h> - -namespace android { - -struct ThreadedSource : public MediaSource { - ThreadedSource(const sp<MediaSource> &source); - - virtual status_t start(MetaData *params); - virtual status_t stop(); - - virtual sp<MetaData> getFormat(); - - virtual status_t read( - MediaBuffer **buffer, const ReadOptions *options); - - virtual void onMessageReceived(const sp<AMessage> &msg); - -protected: - virtual ~ThreadedSource(); - -private: - enum { - kWhatDecodeMore = 'deco', - kWhatSeek = 'seek', - }; - - sp<MediaSource> mSource; - sp<AHandlerReflector<ThreadedSource> > mReflector; - sp<ALooper> mLooper; - - Mutex mLock; - Condition mCondition; - List<MediaBuffer *> mQueue; - status_t mFinalResult; - bool mDecodePending; - bool mStarted; - - int64_t mSeekTimeUs; - ReadOptions::SeekMode mSeekMode; - - void postDecodeMore_l(); - void clearQueue_l(); - - DISALLOW_EVIL_CONSTRUCTORS(ThreadedSource); -}; - -} // namespace android - -#endif // THREADED_SOURCE_H_ diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index d23aa3a..25f30d6 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -20,8 +20,6 @@ #include <dlfcn.h> -#include <sys/prctl.h> - #include "../include/OMX.h" #include "../include/OMXNodeInstance.h" @@ -38,11 +36,32 @@ namespace android { //////////////////////////////////////////////////////////////////////////////// +// This provides the underlying Thread used by CallbackDispatcher. +// Note that deriving CallbackDispatcher from Thread does not work. + +struct OMX::CallbackDispatcherThread : public Thread { + CallbackDispatcherThread(CallbackDispatcher *dispatcher) + : mDispatcher(dispatcher) { + } + +private: + CallbackDispatcher *mDispatcher; + + bool threadLoop(); + + CallbackDispatcherThread(const CallbackDispatcherThread &); + CallbackDispatcherThread &operator=(const CallbackDispatcherThread &); +}; + +//////////////////////////////////////////////////////////////////////////////// + struct OMX::CallbackDispatcher : public RefBase { CallbackDispatcher(OMXNodeInstance *owner); void post(const omx_message &msg); + bool loop(); + protected: virtual ~CallbackDispatcher(); @@ -54,13 +73,10 @@ private: Condition mQueueChanged; List<omx_message> mQueue; - pthread_t mThread; + sp<CallbackDispatcherThread> mThread; void dispatch(const omx_message &msg); - static void *ThreadWrapper(void *me); - void threadEntry(); - CallbackDispatcher(const CallbackDispatcher &); CallbackDispatcher &operator=(const CallbackDispatcher &); }; @@ -68,13 +84,8 @@ private: OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner) : mOwner(owner), mDone(false) { - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - - pthread_create(&mThread, &attr, ThreadWrapper, this); - - pthread_attr_destroy(&attr); + mThread = new CallbackDispatcherThread(this); + mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_AUDIO); } OMX::CallbackDispatcher::~CallbackDispatcher() { @@ -86,10 +97,8 @@ OMX::CallbackDispatcher::~CallbackDispatcher() { } // Don't call join on myself - CHECK(mThread != pthread_self()); - - void *dummy; - pthread_join(mThread, &dummy); + status_t status = mThread->join(); + CHECK(status == NO_ERROR); } void OMX::CallbackDispatcher::post(const omx_message &msg) { @@ -107,17 +116,7 @@ void OMX::CallbackDispatcher::dispatch(const omx_message &msg) { mOwner->onMessage(msg); } -// static -void *OMX::CallbackDispatcher::ThreadWrapper(void *me) { - static_cast<CallbackDispatcher *>(me)->threadEntry(); - - return NULL; -} - -void OMX::CallbackDispatcher::threadEntry() { - androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); - prctl(PR_SET_NAME, (unsigned long)"OMXCallbackDisp", 0, 0, 0); - +bool OMX::CallbackDispatcher::loop() { for (;;) { omx_message msg; @@ -137,6 +136,14 @@ void OMX::CallbackDispatcher::threadEntry() { dispatch(msg); } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// + +bool OMX::CallbackDispatcherThread::threadLoop() { + return mDispatcher->loop(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp index 072d6b2..b398c9d 100644 --- a/media/libstagefright/rtsp/ARTSPConnection.cpp +++ b/media/libstagefright/rtsp/ARTSPConnection.cpp @@ -34,7 +34,7 @@ #include <openssl/md5.h> #include <sys/socket.h> -#include "HTTPStream.h" +#include "HTTPBase.h" namespace android { @@ -251,7 +251,7 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) { mSocket = socket(AF_INET, SOCK_STREAM, 0); if (mUIDValid) { - HTTPStream::RegisterSocketUser(mSocket, mUID); + HTTPBase::RegisterSocketUser(mSocket, mUID); } MakeSocketBlocking(mSocket, false); diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index 3188959..71d68f6 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -40,7 +40,7 @@ #include <sys/socket.h> #include <netdb.h> -#include "HTTPStream.h" +#include "HTTPBase.h" // If no access units are received within 5 secs, assume that the rtp // stream has ended and signal end of stream. @@ -1181,8 +1181,8 @@ private: &info->mRTPSocket, &info->mRTCPSocket, &rtpPort); if (mUIDValid) { - HTTPStream::RegisterSocketUser(info->mRTPSocket, mUID); - HTTPStream::RegisterSocketUser(info->mRTCPSocket, mUID); + HTTPBase::RegisterSocketUser(info->mRTPSocket, mUID); + HTTPBase::RegisterSocketUser(info->mRTCPSocket, mUID); } request.append("Transport: RTP/AVP/UDP;unicast;client_port="); diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index 47ca3a0..8e16d94 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -48,9 +48,6 @@ static const int kDumpLockRetries = 50; static const int kDumpLockSleep = 20000; static bool checkPermission() { -#ifndef HAVE_ANDROID_OS - return true; -#endif if (getpid() == IPCThreadState::self()->getCallingPid()) return true; bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")); if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS"); diff --git a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp index f86ca47..e390ae2 100644 --- a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp +++ b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp @@ -29,7 +29,6 @@ #include <camera/ICamera.h> #include <camera/ICameraClient.h> #include <camera/ICameraService.h> -#include <ui/Overlay.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/ProcessState.h> @@ -311,8 +310,6 @@ public: virtual status_t registerBuffers(const BufferHeap& buffers); virtual void postBuffer(ssize_t offset); virtual void unregisterBuffers(); - virtual sp<OverlayRef> createOverlay( - uint32_t w, uint32_t h, int32_t format, int32_t orientation); virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage); virtual status_t setBufferCount(int bufferCount); @@ -381,13 +378,6 @@ void MSurface::waitUntil(int c0, int c1, int c2) { } } -sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format, - int32_t orientation) { - // Not implemented. - ASSERT(0); - return NULL; -} - // // Utilities to use the Holder service // diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h index cc80062..8902f7a 100644 --- a/services/input/InputApplication.h +++ b/services/input/InputApplication.h @@ -26,26 +26,32 @@ namespace android { /* - * A handle to an application that can receive input. - * Used by the native input dispatcher to indirectly refer to the window manager objects + * Describes the properties of an application that can receive input. + * + * Used by the native input dispatcher as a handle for the window manager objects * that describe an application. */ class InputApplicationHandle : public RefBase { +public: + String8 name; + nsecs_t dispatchingTimeout; + + /** + * Requests that the state of this object be updated to reflect + * the most current available information about the application. + * + * This method should only be called from within the input dispatcher's + * critical section. + * + * Returns true on success, or false if the handle is no longer valid. + */ + virtual bool update() = 0; + protected: InputApplicationHandle() { } virtual ~InputApplicationHandle() { } }; - -/* - * An input application describes properties of an application that can receive input. - */ -struct InputApplication { - sp<InputApplicationHandle> inputApplicationHandle; - String8 name; - nsecs_t dispatchingTimeout; -}; - } // namespace android #endif // _UI_INPUT_APPLICATION_H diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index da9b55c..1cac502 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -211,11 +211,8 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(NULL), mDispatchEnabled(true), mDispatchFrozen(false), mInputFilterEnabled(false), - mFocusedWindow(NULL), - mFocusedApplication(NULL), mCurrentInputTargetsValid(false), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE), - mLastHoverWindow(NULL) { + mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); mInboundQueue.headSentinel.refCount = -1; @@ -501,16 +498,15 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY - && mInputTargetWaitApplication != NULL) { + && mInputTargetWaitApplicationHandle != NULL) { int32_t x = int32_t(motionEntry->firstSample.pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(motionEntry->firstSample.pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_Y)); - const InputWindow* touchedWindow = findTouchedWindowAtLocked(x, y); - if (touchedWindow - && touchedWindow->inputWindowHandle != NULL - && touchedWindow->inputWindowHandle->getInputApplicationHandle() - != mInputTargetWaitApplication) { + sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(x, y); + if (touchedWindowHandle != NULL + && touchedWindowHandle->inputApplicationHandle + != mInputTargetWaitApplicationHandle) { // User touched a different application than the one we are waiting on. // Flag the event, and start pruning the input queue. mNextUnblockedEvent = motionEntry; @@ -524,25 +520,25 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { return needWake; } -const InputWindow* InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) { +sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) { // Traverse windows from front to back to find touched window. - size_t numWindows = mWindows.size(); + size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { - const InputWindow* window = & mWindows.editItemAt(i); - int32_t flags = window->layoutParamsFlags; - - if (window->visible) { - if (!(flags & InputWindow::FLAG_NOT_TOUCHABLE)) { - bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE - | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || window->touchableRegionContainsPoint(x, y)) { + sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i); + int32_t flags = windowHandle->layoutParamsFlags; + + if (windowHandle->visible) { + if (!(flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) { + bool isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE + | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0; + if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) { // Found window. - return window; + return windowHandle; } } } - if (flags & InputWindow::FLAG_SYSTEM_ERROR) { + if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) { // Error window is on top but not visible, so touch is dropped. return NULL; } @@ -781,8 +777,8 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); - if (mFocusedWindow) { - commandEntry->inputWindowHandle = mFocusedWindow->inputWindowHandle; + if (mFocusedWindowHandle != NULL) { + commandEntry->inputWindowHandle = mFocusedWindowHandle; } commandEntry->keyEntry = entry; entry->refCount += 1; @@ -1011,7 +1007,7 @@ void InputDispatcher::resetTargetsLocked() { mCurrentInputTargetsValid = false; mCurrentInputTargets.clear(); mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; - mInputTargetWaitApplication.clear(); + mInputTargetWaitApplicationHandle.clear(); } void InputDispatcher::commitTargetsLocked() { @@ -1019,9 +1015,11 @@ void InputDispatcher::commitTargetsLocked() { } int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, - const EventEntry* entry, const InputApplication* application, const InputWindow* window, + const EventEntry* entry, + const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle, nsecs_t* nextWakeupTime) { - if (application == NULL && window == NULL) { + if (applicationHandle == NULL && windowHandle == NULL) { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { #if DEBUG_FOCUS LOGD("Waiting for system to become ready for input."); @@ -1030,29 +1028,29 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = LONG_LONG_MAX; mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplication.clear(); + mInputTargetWaitApplicationHandle.clear(); } } else { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { #if DEBUG_FOCUS LOGD("Waiting for application to become ready for input: %s", - getApplicationWindowLabelLocked(application, window).string()); + getApplicationWindowLabelLocked(applicationHandle, windowHandle).string()); #endif - nsecs_t timeout = window ? window->dispatchingTimeout : - application ? application->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT; + nsecs_t timeout = windowHandle != NULL ? windowHandle->dispatchingTimeout : + applicationHandle != NULL ? + applicationHandle->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT; mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = currentTime + timeout; mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplication.clear(); + mInputTargetWaitApplicationHandle.clear(); - if (window && window->inputWindowHandle != NULL) { - mInputTargetWaitApplication = - window->inputWindowHandle->getInputApplicationHandle(); + if (windowHandle != NULL) { + mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle; } - if (mInputTargetWaitApplication == NULL && application) { - mInputTargetWaitApplication = application->inputApplicationHandle; + if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) { + mInputTargetWaitApplicationHandle = applicationHandle; } } } @@ -1062,7 +1060,8 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, } if (currentTime >= mInputTargetWaitTimeoutTime) { - onANRLocked(currentTime, application, window, entry->eventTime, mInputTargetWaitStartTime); + onANRLocked(currentTime, applicationHandle, windowHandle, + entry->eventTime, mInputTargetWaitStartTime); // Force poll loop to wake up immediately on next iteration once we get the // ANR response back from the policy. @@ -1129,15 +1128,15 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, // If there is no currently focused window and no focused application // then drop the event. - if (! mFocusedWindow) { - if (mFocusedApplication) { + if (mFocusedWindowHandle == NULL) { + if (mFocusedApplicationHandle != NULL) { #if DEBUG_FOCUS LOGD("Waiting because there is no focused window but there is a " "focused application that may eventually add a window: %s.", - getApplicationWindowLabelLocked(mFocusedApplication, NULL).string()); + getApplicationWindowLabelLocked(mFocusedApplicationHandle, NULL).string()); #endif injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplication, NULL, nextWakeupTime); + mFocusedApplicationHandle, NULL, nextWakeupTime); goto Unresponsive; } @@ -1147,34 +1146,34 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, } // Check permissions. - if (! checkInjectionPermission(mFocusedWindow, entry->injectionState)) { + if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; goto Failed; } // If the currently focused window is paused then keep waiting. - if (mFocusedWindow->paused) { + if (mFocusedWindowHandle->paused) { #if DEBUG_FOCUS LOGD("Waiting because focused window is paused."); #endif injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplication, mFocusedWindow, nextWakeupTime); + mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime); goto Unresponsive; } // If the currently focused window is still working on previous events then keep waiting. - if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) { + if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindowHandle)) { #if DEBUG_FOCUS LOGD("Waiting because focused window still processing previous input."); #endif injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplication, mFocusedWindow, nextWakeupTime); + mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime); goto Unresponsive; } // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - addWindowTargetLocked(mFocusedWindow, + addWindowTargetLocked(mFocusedWindowHandle, InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0)); // Done. @@ -1236,7 +1235,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // Update the touch state as needed based on the properties of the touch event. int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING; InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; - const InputWindow* newHoverWindow = NULL; + sp<InputWindowHandle> newHoverWindowHandle; bool isSplit = mTouchState.split; bool switchedDevice = mTouchState.deviceId >= 0 @@ -1279,42 +1278,44 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(sample->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_Y)); - const InputWindow* newTouchedWindow = NULL; - const InputWindow* topErrorWindow = NULL; + sp<InputWindowHandle> newTouchedWindowHandle; + sp<InputWindowHandle> topErrorWindowHandle; bool isTouchModal = false; // Traverse windows from front to back to find touched window and outside targets. - size_t numWindows = mWindows.size(); + size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { - const InputWindow* window = & mWindows.editItemAt(i); - int32_t flags = window->layoutParamsFlags; + sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i); + int32_t flags = windowHandle->layoutParamsFlags; - if (flags & InputWindow::FLAG_SYSTEM_ERROR) { - if (! topErrorWindow) { - topErrorWindow = window; + if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) { + if (topErrorWindowHandle == NULL) { + topErrorWindowHandle = windowHandle; } } - if (window->visible) { - if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) { - isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE - | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || window->touchableRegionContainsPoint(x, y)) { - if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) { - newTouchedWindow = window; + if (windowHandle->visible) { + if (! (flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) { + isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE + | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0; + if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) { + if (! screenWasOff + || (flags & InputWindowHandle::FLAG_TOUCHABLE_WHEN_WAKING)) { + newTouchedWindowHandle = windowHandle; } break; // found touched window, exit window loop } } if (maskedAction == AMOTION_EVENT_ACTION_DOWN - && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) { + && (flags & InputWindowHandle::FLAG_WATCH_OUTSIDE_TOUCH)) { int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; - if (isWindowObscuredAtPointLocked(window, x, y)) { + if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } - mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0)); + mTempTouchState.addOrUpdateWindow( + windowHandle, outsideTargetFlags, BitSet32(0)); } } } @@ -1322,7 +1323,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // If there is an error window but it is not taking focus (typically because // it is invisible) then wait for it. Any other focused window may in // fact be in ANR state. - if (topErrorWindow && newTouchedWindow != topErrorWindow) { + if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) { #if DEBUG_FOCUS LOGD("Waiting because system error window is pending."); #endif @@ -1333,26 +1334,26 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } // Figure out whether splitting will be allowed for this window. - if (newTouchedWindow && newTouchedWindow->supportsSplitTouch()) { + if (newTouchedWindowHandle != NULL && newTouchedWindowHandle->supportsSplitTouch()) { // New window supports splitting. isSplit = true; } else if (isSplit) { // New window does not support splitting but we have already split events. // Assign the pointer to the first foreground window we find. // (May be NULL which is why we put this code block before the next check.) - newTouchedWindow = mTempTouchState.getFirstForegroundWindow(); + newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); } // If we did not find a touched window then fail. - if (! newTouchedWindow) { - if (mFocusedApplication) { + if (newTouchedWindowHandle == NULL) { + if (mFocusedApplicationHandle != NULL) { #if DEBUG_FOCUS LOGD("Waiting because there is no touched window but there is a " "focused application that may eventually add a new window: %s.", - getApplicationWindowLabelLocked(mFocusedApplication, NULL).string()); + getApplicationWindowLabelLocked(mFocusedApplicationHandle, NULL).string()); #endif injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplication, NULL, nextWakeupTime); + mFocusedApplicationHandle, NULL, nextWakeupTime); goto Unresponsive; } @@ -1366,20 +1367,20 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; } - if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) { + if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } // Update hover state. if (isHoverAction) { - newHoverWindow = newTouchedWindow; + newHoverWindowHandle = newTouchedWindowHandle; // Ensure all subsequent motion samples are also within the touched window. // Set *outSplitBatchAfterSample to the sample before the first one that is not // within the touched window. if (!isTouchModal) { while (sample->next) { - if (!newHoverWindow->touchableRegionContainsPoint( + if (!newHoverWindowHandle->touchableRegionContainsPoint( sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) { *outSplitBatchAfterSample = sample; @@ -1389,7 +1390,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } } } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { - newHoverWindow = mLastHoverWindow; + newHoverWindowHandle = mLastHoverWindowHandle; } // Update the temporary touch state. @@ -1398,7 +1399,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, uint32_t pointerId = entry->pointerProperties[pointerIndex].id; pointerIds.markBit(pointerId); } - mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds); + mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ @@ -1420,19 +1421,22 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, int32_t x = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); - const InputWindow* oldTouchedWindow = mTempTouchState.getFirstForegroundWindow(); - const InputWindow* newTouchedWindow = findTouchedWindowAtLocked(x, y); - if (oldTouchedWindow != newTouchedWindow && newTouchedWindow) { + sp<InputWindowHandle> oldTouchedWindowHandle = + mTempTouchState.getFirstForegroundWindowHandle(); + sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(x, y); + if (oldTouchedWindowHandle != newTouchedWindowHandle + && newTouchedWindowHandle != NULL) { #if DEBUG_FOCUS LOGD("Touch is slipping out of window %s into window %s.", - oldTouchedWindow->name.string(), newTouchedWindow->name.string()); + oldTouchedWindowHandle->name.string(), + newTouchedWindowHandle->name.string()); #endif // Make a slippery exit from the old window. - mTempTouchState.addOrUpdateWindow(oldTouchedWindow, + mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0)); // Make a slippery entrance into the new window. - if (newTouchedWindow->supportsSplitTouch()) { + if (newTouchedWindowHandle->supportsSplitTouch()) { isSplit = true; } @@ -1441,7 +1445,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; } - if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) { + if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } @@ -1449,7 +1453,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (isSplit) { pointerIds.markBit(entry->pointerProperties[0].id); } - mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds); + mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); // Split the batch here so we send exactly one sample. *outSplitBatchAfterSample = &entry->firstSample; @@ -1457,25 +1461,25 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } } - if (newHoverWindow != mLastHoverWindow) { + if (newHoverWindowHandle != mLastHoverWindowHandle) { // Split the batch here so we send exactly one sample as part of ENTER or EXIT. *outSplitBatchAfterSample = &entry->firstSample; // Let the previous window know that the hover sequence is over. - if (mLastHoverWindow) { + if (mLastHoverWindowHandle != NULL) { #if DEBUG_HOVER - LOGD("Sending hover exit event to window %s.", mLastHoverWindow->name.string()); + LOGD("Sending hover exit event to window %s.", mLastHoverWindowHandle->name.string()); #endif - mTempTouchState.addOrUpdateWindow(mLastHoverWindow, + mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); } // Let the new window know that the hover sequence is starting. - if (newHoverWindow) { + if (newHoverWindowHandle != NULL) { #if DEBUG_HOVER - LOGD("Sending hover enter event to window %s.", newHoverWindow->name.string()); + LOGD("Sending hover enter event to window %s.", newHoverWindowHandle->name.string()); #endif - mTempTouchState.addOrUpdateWindow(newHoverWindow, + mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0)); } } @@ -1488,7 +1492,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { haveForegroundWindow = true; - if (! checkInjectionPermission(touchedWindow.window, entry->injectionState)) { + if (! checkInjectionPermission(touchedWindow.windowHandle, + entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; goto Failed; @@ -1510,14 +1515,15 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // Check whether windows listening for outside touches are owned by the same UID. If it is // set the policy flag that we will not reveal coordinate information to this window. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow(); - const int32_t foregroundWindowUid = foregroundWindow->ownerUid; + sp<InputWindowHandle> foregroundWindowHandle = + mTempTouchState.getFirstForegroundWindowHandle(); + const int32_t foregroundWindowUid = foregroundWindowHandle->ownerUid; for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - const InputWindow* inputWindow = touchedWindow.window; - if (inputWindow->ownerUid != foregroundWindowUid) { - mTempTouchState.addOrUpdateWindow(inputWindow, + sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle; + if (inputWindowHandle->ownerUid != foregroundWindowUid) { + mTempTouchState.addOrUpdateWindow(inputWindowHandle, InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); } } @@ -1529,22 +1535,22 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { // If the touched window is paused then keep waiting. - if (touchedWindow.window->paused) { + if (touchedWindow.windowHandle->paused) { #if DEBUG_FOCUS LOGD("Waiting because touched window is paused."); #endif injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.window, nextWakeupTime); + NULL, touchedWindow.windowHandle, nextWakeupTime); goto Unresponsive; } // If the touched window is still working on previous events then keep waiting. - if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.window)) { + if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS LOGD("Waiting because touched window still processing previous input."); #endif injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.window, nextWakeupTime); + NULL, touchedWindow.windowHandle, nextWakeupTime); goto Unresponsive; } } @@ -1557,12 +1563,13 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // engine only supports touch events. We would need to add a mechanism similar // to View.onGenericMotionEvent to enable wallpapers to handle these events. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow(); - if (foregroundWindow->hasWallpaper) { - for (size_t i = 0; i < mWindows.size(); i++) { - const InputWindow* window = & mWindows[i]; - if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) { - mTempTouchState.addOrUpdateWindow(window, + sp<InputWindowHandle> foregroundWindowHandle = + mTempTouchState.getFirstForegroundWindowHandle(); + if (foregroundWindowHandle->hasWallpaper) { + for (size_t i = 0; i < mWindowHandles.size(); i++) { + sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i); + if (windowHandle->layoutParamsType == InputWindowHandle::TYPE_WALLPAPER) { + mTempTouchState.addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0)); @@ -1576,7 +1583,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i); - addWindowTargetLocked(touchedWindow.window, touchedWindow.targetFlags, + addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, touchedWindow.pointerIds); } @@ -1658,7 +1665,7 @@ Failed: } // Update hover state. - mLastHoverWindow = newHoverWindow; + mLastHoverWindowHandle = newHoverWindowHandle; } } else { #if DEBUG_FOCUS @@ -1681,16 +1688,16 @@ Unresponsive: return injectionResult; } -void InputDispatcher::addWindowTargetLocked(const InputWindow* window, int32_t targetFlags, - BitSet32 pointerIds) { +void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, + int32_t targetFlags, BitSet32 pointerIds) { mCurrentInputTargets.push(); InputTarget& target = mCurrentInputTargets.editTop(); - target.inputChannel = window->inputChannel; + target.inputChannel = windowHandle->inputChannel; target.flags = targetFlags; - target.xOffset = - window->frameLeft; - target.yOffset = - window->frameTop; - target.scaleFactor = window->scaleFactor; + target.xOffset = - windowHandle->frameLeft; + target.yOffset = - windowHandle->frameTop; + target.scaleFactor = windowHandle->scaleFactor; target.pointerIds = pointerIds; } @@ -1708,17 +1715,17 @@ void InputDispatcher::addMonitoringTargetsLocked() { } } -bool InputDispatcher::checkInjectionPermission(const InputWindow* window, +bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, const InjectionState* injectionState) { if (injectionState - && (window == NULL || window->ownerUid != injectionState->injectorUid) + && (windowHandle == NULL || windowHandle->ownerUid != injectionState->injectorUid) && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { - if (window) { - LOGW("Permission denied: injecting event from pid %d uid %d to window " - "with input channel %s owned by uid %d", + if (windowHandle != NULL) { + LOGW("Permission denied: injecting event from pid %d uid %d to window %s " + "owned by uid %d", injectionState->injectorPid, injectionState->injectorUid, - window->inputChannel->getName().string(), - window->ownerUid); + windowHandle->name.string(), + windowHandle->ownerUid); } else { LOGW("Permission denied: injecting event from pid %d uid %d", injectionState->injectorPid, injectionState->injectorUid); @@ -1729,22 +1736,24 @@ bool InputDispatcher::checkInjectionPermission(const InputWindow* window, } bool InputDispatcher::isWindowObscuredAtPointLocked( - const InputWindow* window, int32_t x, int32_t y) const { - size_t numWindows = mWindows.size(); + const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const { + size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { - const InputWindow* other = & mWindows.itemAt(i); - if (other == window) { + sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i); + if (otherHandle == windowHandle) { break; } - if (other->visible && ! other->isTrustedOverlay() && other->frameContainsPoint(x, y)) { + if (otherHandle->visible && ! otherHandle->isTrustedOverlay() + && otherHandle->frameContainsPoint(x, y)) { return true; } } return false; } -bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(const InputWindow* window) { - ssize_t connectionIndex = getConnectionIndexLocked(window->inputChannel); +bool InputDispatcher::isWindowFinishedWithPreviousInputLocked( + const sp<InputWindowHandle>& windowHandle) { + ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->inputChannel); if (connectionIndex >= 0) { sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); return connection->outboundQueue.isEmpty(); @@ -1753,19 +1762,20 @@ bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(const InputWindow* } } -String8 InputDispatcher::getApplicationWindowLabelLocked(const InputApplication* application, - const InputWindow* window) { - if (application) { - if (window) { - String8 label(application->name); +String8 InputDispatcher::getApplicationWindowLabelLocked( + const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle) { + if (applicationHandle != NULL) { + if (windowHandle != NULL) { + String8 label(applicationHandle->name); label.append(" - "); - label.append(window->name); + label.append(windowHandle->name); return label; } else { - return application->name; + return applicationHandle->name; } - } else if (window) { - return window->name; + } else if (windowHandle != NULL) { + return windowHandle->name; } else { return String8("<unknown application or window>"); } @@ -2422,11 +2432,11 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } InputTarget target; - const InputWindow* window = getWindowLocked(connection->inputChannel); - if (window) { - target.xOffset = -window->frameLeft; - target.yOffset = -window->frameTop; - target.scaleFactor = window->scaleFactor; + sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel); + if (windowHandle != NULL) { + target.xOffset = -windowHandle->frameLeft; + target.yOffset = -windowHandle->frameTop; + target.scaleFactor = windowHandle->scaleFactor; } else { target.xOffset = 0; target.yOffset = 0; @@ -2809,7 +2819,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t } if (action == AMOTION_EVENT_ACTION_HOVER_MOVE) { - if (!mLastHoverWindow) { + if (mLastHoverWindowHandle == NULL) { #if DEBUG_BATCHING LOGD("Not streaming hover move because there is no " "last hovered window."); @@ -2817,15 +2827,16 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t goto NoBatchingOrStreaming; } - const InputWindow* hoverWindow = findTouchedWindowAtLocked( + sp<InputWindowHandle> hoverWindowHandle = findTouchedWindowAtLocked( pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); - if (mLastHoverWindow != hoverWindow) { + if (mLastHoverWindowHandle != hoverWindowHandle) { #if DEBUG_BATCHING LOGD("Not streaming hover move because the last hovered window " "is '%s' but the currently hovered window is '%s'.", - mLastHoverWindow->name.string(), - hoverWindow ? hoverWindow->name.string() : "<null>"); + mLastHoverWindowHandle->name.string(), + hoverWindowHandle != NULL + ? hoverWindowHandle->name.string() : "<null>"); #endif goto NoBatchingOrStreaming; } @@ -3125,111 +3136,109 @@ void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* ent } } -const InputWindow* InputDispatcher::getWindowLocked(const sp<InputChannel>& inputChannel) { - for (size_t i = 0; i < mWindows.size(); i++) { - const InputWindow* window = & mWindows[i]; - if (window->inputChannel == inputChannel) { - return window; +sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked( + const sp<InputChannel>& inputChannel) const { + size_t numWindows = mWindowHandles.size(); + for (size_t i = 0; i < numWindows; i++) { + const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); + if (windowHandle->inputChannel == inputChannel) { + return windowHandle; } } return NULL; } -void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) { +bool InputDispatcher::hasWindowHandleLocked( + const sp<InputWindowHandle>& windowHandle) const { + size_t numWindows = mWindowHandles.size(); + for (size_t i = 0; i < numWindows; i++) { + if (mWindowHandles.itemAt(i) == windowHandle) { + return true; + } + } + return false; +} + +void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) { #if DEBUG_FOCUS LOGD("setInputWindows"); #endif { // acquire lock AutoMutex _l(mLock); - // Clear old window pointers. - sp<InputChannel> oldFocusedWindowChannel; - if (mFocusedWindow) { - oldFocusedWindowChannel = mFocusedWindow->inputChannel; - mFocusedWindow = NULL; - } - sp<InputChannel> oldLastHoverWindowChannel; - if (mLastHoverWindow) { - oldLastHoverWindowChannel = mLastHoverWindow->inputChannel; - mLastHoverWindow = NULL; - } - - // Loop over new windows and rebuild the necessary window pointers for - // tracking focus and touch. - mWindows = inputWindows; + mWindowHandles = inputWindowHandles; - size_t numWindows = mWindows.size(); - for (size_t i = 0; i < numWindows; i++) { - const InputWindow* window = & mWindows.itemAt(i); - if (window->hasFocus) { - mFocusedWindow = window; - break; + sp<InputWindowHandle> newFocusedWindowHandle; + bool foundHoveredWindow = false; + for (size_t i = 0; i < mWindowHandles.size(); i++) { + const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); + if (!windowHandle->update() || windowHandle->inputChannel == NULL) { + mWindowHandles.removeAt(i--); + continue; } + if (windowHandle->hasFocus) { + newFocusedWindowHandle = windowHandle; + } + if (windowHandle == mLastHoverWindowHandle) { + foundHoveredWindow = true; + } + } + + if (!foundHoveredWindow) { + mLastHoverWindowHandle = NULL; } - if (oldFocusedWindowChannel != NULL) { - if (!mFocusedWindow || oldFocusedWindowChannel != mFocusedWindow->inputChannel) { + if (mFocusedWindowHandle != newFocusedWindowHandle) { + if (mFocusedWindowHandle != NULL) { #if DEBUG_FOCUS LOGD("Focus left window: %s", - oldFocusedWindowChannel->getName().string()); + mFocusedWindowHandle->name.string()); #endif CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, "focus left window"); - synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel, options); - oldFocusedWindowChannel.clear(); + synthesizeCancelationEventsForInputChannelLocked( + mFocusedWindowHandle->inputChannel, options); } - } - if (mFocusedWindow && oldFocusedWindowChannel == NULL) { + if (newFocusedWindowHandle != NULL) { #if DEBUG_FOCUS - LOGD("Focus entered window: %s", - mFocusedWindow->inputChannel->getName().string()); + LOGD("Focus entered window: %s", + newFocusedWindowHandle->name.string()); #endif + } + mFocusedWindowHandle = newFocusedWindowHandle; } - for (size_t i = 0; i < mTouchState.windows.size(); ) { + for (size_t i = 0; i < mTouchState.windows.size(); i++) { TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i); - const InputWindow* window = getWindowLocked(touchedWindow.channel); - if (window) { - touchedWindow.window = window; - i += 1; - } else { + if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS - LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string()); + LOGD("Touched window was removed: %s", touchedWindow.windowHandle->name.string()); #endif CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "touched window was removed"); - synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel, options); - mTouchState.windows.removeAt(i); + synthesizeCancelationEventsForInputChannelLocked( + touchedWindow.windowHandle->inputChannel, options); + mTouchState.windows.removeAt(i--); } } - - // Recover the last hovered window. - if (oldLastHoverWindowChannel != NULL) { - mLastHoverWindow = getWindowLocked(oldLastHoverWindowChannel); - oldLastHoverWindowChannel.clear(); - } - -#if DEBUG_FOCUS - //logDispatchStateLocked(); -#endif } // release lock // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake(); } -void InputDispatcher::setFocusedApplication(const InputApplication* inputApplication) { +void InputDispatcher::setFocusedApplication( + const sp<InputApplicationHandle>& inputApplicationHandle) { #if DEBUG_FOCUS LOGD("setFocusedApplication"); #endif { // acquire lock AutoMutex _l(mLock); - releaseFocusedApplicationLocked(); - - if (inputApplication) { - mFocusedApplicationStorage = *inputApplication; - mFocusedApplication = & mFocusedApplicationStorage; + if (inputApplicationHandle != NULL && inputApplicationHandle->update()) { + mFocusedApplicationHandle = inputApplicationHandle; + } else { + mFocusedApplicationHandle.clear(); } #if DEBUG_FOCUS @@ -3241,13 +3250,6 @@ void InputDispatcher::setFocusedApplication(const InputApplication* inputApplica mLooper->wake(); } -void InputDispatcher::releaseFocusedApplicationLocked() { - if (mFocusedApplication) { - mFocusedApplication = NULL; - mFocusedApplicationStorage.inputApplicationHandle.clear(); - } -} - void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { #if DEBUG_FOCUS LOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen); @@ -3313,15 +3315,15 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, { // acquire lock AutoMutex _l(mLock); - const InputWindow* fromWindow = getWindowLocked(fromChannel); - const InputWindow* toWindow = getWindowLocked(toChannel); - if (! fromWindow || ! toWindow) { + sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel); + sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel); + if (fromWindowHandle == NULL || toWindowHandle == NULL) { #if DEBUG_FOCUS LOGD("Cannot transfer focus because from or to window not found."); #endif return false; } - if (fromWindow == toWindow) { + if (fromWindowHandle == toWindowHandle) { #if DEBUG_FOCUS LOGD("Trivial transfer to same window."); #endif @@ -3331,7 +3333,7 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, bool found = false; for (size_t i = 0; i < mTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTouchState.windows[i]; - if (touchedWindow.window == fromWindow) { + if (touchedWindow.windowHandle == fromWindowHandle) { int32_t oldTargetFlags = touchedWindow.targetFlags; BitSet32 pointerIds = touchedWindow.pointerIds; @@ -3340,7 +3342,7 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, int32_t newTargetFlags = oldTargetFlags & (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); - mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds); + mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); found = true; break; @@ -3390,7 +3392,7 @@ void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { resetTargetsLocked(); mTouchState.reset(); - mLastHoverWindow = NULL; + mLastHoverWindowHandle.clear(); } void InputDispatcher::logDispatchStateLocked() { @@ -3413,15 +3415,15 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); - if (mFocusedApplication) { + if (mFocusedApplicationHandle != NULL) { dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", - mFocusedApplication->name.string(), - mFocusedApplication->dispatchingTimeout / 1000000.0); + mFocusedApplicationHandle->name.string(), + mFocusedApplicationHandle->dispatchingTimeout / 1000000.0); } else { dump.append(INDENT "FocusedApplication: <null>\n"); } dump.appendFormat(INDENT "FocusedWindow: name='%s'\n", - mFocusedWindow != NULL ? mFocusedWindow->name.string() : "<null>"); + mFocusedWindowHandle != NULL ? mFocusedWindowHandle->name.string() : "<null>"); dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down)); dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split)); @@ -3432,37 +3434,37 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { for (size_t i = 0; i < mTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTouchState.windows[i]; dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.window->name.string(), touchedWindow.pointerIds.value, + i, touchedWindow.windowHandle->name.string(), touchedWindow.pointerIds.value, touchedWindow.targetFlags); } } else { dump.append(INDENT "TouchedWindows: <none>\n"); } - if (!mWindows.isEmpty()) { + if (!mWindowHandles.isEmpty()) { dump.append(INDENT "Windows:\n"); - for (size_t i = 0; i < mWindows.size(); i++) { - const InputWindow& window = mWindows[i]; + for (size_t i = 0; i < mWindowHandles.size(); i++) { + const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, " "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " "frame=[%d,%d][%d,%d], scale=%f, " "touchableRegion=", - i, window.name.string(), - toString(window.paused), - toString(window.hasFocus), - toString(window.hasWallpaper), - toString(window.visible), - toString(window.canReceiveKeys), - window.layoutParamsFlags, window.layoutParamsType, - window.layer, - window.frameLeft, window.frameTop, - window.frameRight, window.frameBottom, - window.scaleFactor); - dumpRegion(dump, window.touchableRegion); - dump.appendFormat(", inputFeatures=0x%08x", window.inputFeatures); + i, windowHandle->name.string(), + toString(windowHandle->paused), + toString(windowHandle->hasFocus), + toString(windowHandle->hasWallpaper), + toString(windowHandle->visible), + toString(windowHandle->canReceiveKeys), + windowHandle->layoutParamsFlags, windowHandle->layoutParamsType, + windowHandle->layer, + windowHandle->frameLeft, windowHandle->frameTop, + windowHandle->frameRight, windowHandle->frameBottom, + windowHandle->scaleFactor); + dumpRegion(dump, windowHandle->touchableRegion); + dump.appendFormat(", inputFeatures=0x%08x", windowHandle->inputFeatures); dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", - window.ownerPid, window.ownerUid, - window.dispatchingTimeout / 1000000.0); + windowHandle->ownerPid, windowHandle->ownerUid, + windowHandle->dispatchingTimeout / 1000000.0); } } else { dump.append(INDENT "Windows: <none>\n"); @@ -3634,23 +3636,19 @@ void InputDispatcher::onDispatchCycleBrokenLocked( } void InputDispatcher::onANRLocked( - nsecs_t currentTime, const InputApplication* application, const InputWindow* window, + nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle, nsecs_t eventTime, nsecs_t waitStartTime) { LOGI("Application is not responding: %s. " "%01.1fms since event, %01.1fms since wait started", - getApplicationWindowLabelLocked(application, window).string(), + getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), (currentTime - eventTime) / 1000000.0, (currentTime - waitStartTime) / 1000000.0); CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doNotifyANRLockedInterruptible); - if (application) { - commandEntry->inputApplicationHandle = application->inputApplicationHandle; - } - if (window) { - commandEntry->inputWindowHandle = window->inputWindowHandle; - commandEntry->inputChannel = window->inputChannel; - } + commandEntry->inputApplicationHandle = applicationHandle; + commandEntry->inputWindowHandle = windowHandle; } void InputDispatcher::doNotifyConfigurationChangedInterruptible( @@ -3684,7 +3682,9 @@ void InputDispatcher::doNotifyANRLockedInterruptible( mLock.lock(); - resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputChannel); + resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, + commandEntry->inputWindowHandle != NULL + ? commandEntry->inputWindowHandle->inputChannel : NULL); } void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( @@ -4561,7 +4561,7 @@ void InputDispatcher::TouchState::copyFrom(const TouchState& other) { windows = other.windows; } -void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window, +void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds) { if (targetFlags & InputTarget::FLAG_SPLIT) { split = true; @@ -4569,7 +4569,7 @@ void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window, for (size_t i = 0; i < windows.size(); i++) { TouchedWindow& touchedWindow = windows.editItemAt(i); - if (touchedWindow.window == window) { + if (touchedWindow.windowHandle == windowHandle) { touchedWindow.targetFlags |= targetFlags; if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS; @@ -4582,10 +4582,9 @@ void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window, windows.push(); TouchedWindow& touchedWindow = windows.editTop(); - touchedWindow.window = window; + touchedWindow.windowHandle = windowHandle; touchedWindow.targetFlags = targetFlags; touchedWindow.pointerIds = pointerIds; - touchedWindow.channel = window->inputChannel; } void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { @@ -4602,11 +4601,11 @@ void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { } } -const InputWindow* InputDispatcher::TouchState::getFirstForegroundWindow() const { +sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const { for (size_t i = 0; i < windows.size(); i++) { const TouchedWindow& window = windows.itemAt(i); if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - return window.window; + return window.windowHandle; } } return NULL; @@ -4618,8 +4617,8 @@ bool InputDispatcher::TouchState::isSlippery() const { for (size_t i = 0; i < windows.size(); i++) { const TouchedWindow& window = windows.itemAt(i); if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - if (haveSlipperyForegroundWindow - || !(window.window->layoutParamsFlags & InputWindow::FLAG_SLIPPERY)) { + if (haveSlipperyForegroundWindow || !(window.windowHandle->layoutParamsFlags + & InputWindowHandle::FLAG_SLIPPERY)) { return false; } haveSlipperyForegroundWindow = true; diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index bdd1922..15fd274 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -321,13 +321,14 @@ public: * * This method may be called on any thread (usually by the input manager). */ - virtual void setInputWindows(const Vector<InputWindow>& inputWindows) = 0; + virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0; /* Sets the focused application. * * This method may be called on any thread (usually by the input manager). */ - virtual void setFocusedApplication(const InputApplication* inputApplication) = 0; + virtual void setFocusedApplication( + const sp<InputApplicationHandle>& inputApplicationHandle) = 0; /* Sets the input dispatching mode. * @@ -406,8 +407,8 @@ public: int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags); - virtual void setInputWindows(const Vector<InputWindow>& inputWindows); - virtual void setFocusedApplication(const InputApplication* inputApplication); + virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles); + virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle); virtual void setInputDispatchMode(bool enabled, bool frozen); virtual void setInputFilterEnabled(bool enabled); @@ -578,7 +579,6 @@ private: sp<Connection> connection; nsecs_t eventTime; KeyEntry* keyEntry; - sp<InputChannel> inputChannel; sp<InputApplicationHandle> inputApplicationHandle; sp<InputWindowHandle> inputWindowHandle; int32_t userActivityEventType; @@ -894,7 +894,7 @@ private: // to transfer focus to a new application. EventEntry* mNextUnblockedEvent; - const InputWindow* findTouchedWindowAtLocked(int32_t x, int32_t y); + sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y); // All registered connections mapped by receive pipe file descriptor. KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd; @@ -953,19 +953,19 @@ private: bool mDispatchFrozen; bool mInputFilterEnabled; - Vector<InputWindow> mWindows; + Vector<sp<InputWindowHandle> > mWindowHandles; - const InputWindow* getWindowLocked(const sp<InputChannel>& inputChannel); + sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const; + bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const; // Focus tracking for keys, trackball, etc. - const InputWindow* mFocusedWindow; + sp<InputWindowHandle> mFocusedWindowHandle; // Focus tracking for touch. struct TouchedWindow { - const InputWindow* window; + sp<InputWindowHandle> windowHandle; int32_t targetFlags; BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set - sp<InputChannel> channel; }; struct TouchState { bool down; @@ -978,9 +978,10 @@ private: ~TouchState(); void reset(); void copyFrom(const TouchState& other); - void addOrUpdateWindow(const InputWindow* window,int32_t targetFlags, BitSet32 pointerIds); + void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, + int32_t targetFlags, BitSet32 pointerIds); void filterNonAsIsTouchWindows(); - const InputWindow* getFirstForegroundWindow() const; + sp<InputWindowHandle> getFirstForegroundWindowHandle() const; bool isSlippery() const; }; @@ -988,9 +989,7 @@ private: TouchState mTempTouchState; // Focused application. - InputApplication* mFocusedApplication; - InputApplication mFocusedApplicationStorage; // preallocated storage for mFocusedApplication - void releaseFocusedApplicationLocked(); + sp<InputApplicationHandle> mFocusedApplicationHandle; // Dispatch inbound events. bool dispatchConfigurationChangedLocked( @@ -1021,16 +1020,17 @@ private: nsecs_t mInputTargetWaitStartTime; nsecs_t mInputTargetWaitTimeoutTime; bool mInputTargetWaitTimeoutExpired; - sp<InputApplicationHandle> mInputTargetWaitApplication; + sp<InputApplicationHandle> mInputTargetWaitApplicationHandle; // Contains the last window which received a hover event. - const InputWindow* mLastHoverWindow; + sp<InputWindowHandle> mLastHoverWindowHandle; // Finding targets for input events. void resetTargetsLocked(); void commitTargetsLocked(); int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, - const InputApplication* application, const InputWindow* window, + const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle, nsecs_t* nextWakeupTime); void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, const sp<InputChannel>& inputChannel); @@ -1043,15 +1043,17 @@ private: nsecs_t* nextWakeupTime, bool* outConflictingPointerActions, const MotionSample** outSplitBatchAfterSample); - void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags, - BitSet32 pointerIds); + void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, + int32_t targetFlags, BitSet32 pointerIds); void addMonitoringTargetsLocked(); void pokeUserActivityLocked(const EventEntry* eventEntry); - bool checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState); - bool isWindowObscuredAtPointLocked(const InputWindow* window, int32_t x, int32_t y) const; - bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window); - String8 getApplicationWindowLabelLocked(const InputApplication* application, - const InputWindow* window); + bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, + const InjectionState* injectionState); + bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, + int32_t x, int32_t y) const; + bool isWindowFinishedWithPreviousInputLocked(const sp<InputWindowHandle>& windowHandle); + String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle); // Manage the dispatch cycle for a single connection. // These methods are deliberately not Interruptible because doing all of the work @@ -1100,7 +1102,8 @@ private: void onDispatchCycleBrokenLocked( nsecs_t currentTime, const sp<Connection>& connection); void onANRLocked( - nsecs_t currentTime, const InputApplication* application, const InputWindow* window, + nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle, nsecs_t eventTime, nsecs_t waitStartTime); // Outbound policy interactions. diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp index b552f6d..0ce8867 100644 --- a/services/input/InputWindow.cpp +++ b/services/input/InputWindow.cpp @@ -22,25 +22,25 @@ namespace android { -// --- InputWindow --- +// --- InputWindowHandle --- -bool InputWindow::touchableRegionContainsPoint(int32_t x, int32_t y) const { +bool InputWindowHandle::touchableRegionContainsPoint(int32_t x, int32_t y) const { return touchableRegion.contains(x, y); } -bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const { +bool InputWindowHandle::frameContainsPoint(int32_t x, int32_t y) const { return x >= frameLeft && x <= frameRight && y >= frameTop && y <= frameBottom; } -bool InputWindow::isTrustedOverlay() const { +bool InputWindowHandle::isTrustedOverlay() const { return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; } -bool InputWindow::supportsSplitTouch() const { - return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH; +bool InputWindowHandle::supportsSplitTouch() const { + return layoutParamsFlags & FLAG_SPLIT_TOUCH; } } // namespace android diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h index d166ad4..272081c 100644 --- a/services/input/InputWindow.h +++ b/services/input/InputWindow.h @@ -31,29 +31,14 @@ namespace android { /* * A handle to a window that can receive input. + * * Used by the native input dispatcher to indirectly refer to the window manager objects * that describe a window. */ class InputWindowHandle : public RefBase { -protected: - InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) : - mInputApplicationHandle(inputApplicationHandle) { } - virtual ~InputWindowHandle() { } - public: - inline sp<InputApplicationHandle> getInputApplicationHandle() { - return mInputApplicationHandle; - } - -private: - sp<InputApplicationHandle> mInputApplicationHandle; -}; - + const sp<InputApplicationHandle> inputApplicationHandle; -/* - * An input window describes the bounds of a window that can receive input. - */ -struct InputWindow { // Window flags from WindowManager.LayoutParams enum { FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, @@ -164,6 +149,22 @@ struct InputWindow { bool isTrustedOverlay() const; bool supportsSplitTouch() const; + + /** + * Requests that the state of this object be updated to reflect + * the most current available information about the application. + * + * This method should only be called from within the input dispatcher's + * critical section. + * + * Returns true on success, or false if the handle is no longer valid. + */ + virtual bool update() = 0; + +protected: + InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) : + inputApplicationHandle(inputApplicationHandle) { } + virtual ~InputWindowHandle() { } }; } // namespace android diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 67067de..131894a 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -369,11 +369,12 @@ private: return INPUT_EVENT_INJECTION_FAILED; } - virtual void setInputWindows(const Vector<InputWindow>& inputWindows) { + virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) { ADD_FAILURE() << "Should never be called by input reader."; } - virtual void setFocusedApplication(const InputApplication* inputApplication) { + virtual void setFocusedApplication( + const sp<InputApplicationHandle>& inputApplicationHandle) { ADD_FAILURE() << "Should never be called by input reader."; } diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 786f2fa..168b894 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -76,6 +76,7 @@ import com.android.internal.backup.IBackupTransport; import com.android.internal.backup.LocalTransport; import com.android.server.PackageManagerBackupAgent.Metadata; +import java.io.DataInputStream; import java.io.EOFException; import java.io.File; import java.io.FileDescriptor; @@ -96,6 +97,10 @@ import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; class BackupManagerService extends IBackupManager.Stub { private static final String TAG = "BackupManagerService"; @@ -1679,6 +1684,7 @@ class BackupManagerService extends IBackupManager.Stub { class PerformFullBackupTask implements Runnable { ParcelFileDescriptor mOutputFile; + DeflaterOutputStream mDeflater; IFullBackupRestoreObserver mObserver; boolean mIncludeApks; boolean mIncludeShared; @@ -1688,6 +1694,55 @@ class BackupManagerService extends IBackupManager.Stub { File mFilesDir; File mManifestFile; + class FullBackupRunner implements Runnable { + PackageInfo mPackage; + IBackupAgent mAgent; + ParcelFileDescriptor mPipe; + int mToken; + boolean mSendApk; + + FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe, + int token, boolean sendApk) throws IOException { + mPackage = pack; + mAgent = agent; + mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor()); + mToken = token; + mSendApk = sendApk; + } + + @Override + public void run() { + try { + BackupDataOutput output = new BackupDataOutput( + mPipe.getFileDescriptor()); + + if (DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName); + writeAppManifest(mPackage, mManifestFile, mSendApk); + FullBackup.backupToTar(mPackage.packageName, null, null, + mFilesDir.getAbsolutePath(), + mManifestFile.getAbsolutePath(), + output); + + if (mSendApk) { + writeApkToBackup(mPackage, output); + } + + if (DEBUG) Slog.d(TAG, "Calling doFullBackup()"); + prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL); + mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder); + } catch (IOException e) { + Slog.e(TAG, "Error running full backup for " + mPackage.packageName); + } catch (RemoteException e) { + Slog.e(TAG, "Remote agent vanished during full backup of " + + mPackage.packageName); + } finally { + try { + mPipe.close(); + } catch (IOException e) {} + } + } + } + PerformFullBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, boolean includeApks, boolean includeShared, boolean doAllApps, String[] packages, AtomicBoolean latch) { @@ -1736,13 +1791,21 @@ class BackupManagerService extends IBackupManager.Stub { } } + // Set up the compression stage + FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor()); + Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION); + DeflaterOutputStream out = new DeflaterOutputStream(ofstream, deflater, true); + + // !!! TODO: if using encryption, set up the encryption stage + // and emit the tar header stating the password salt. + PackageInfo pkg = null; try { // Now back up the app data via the agent mechanism int N = packagesToBackup.size(); for (int i = 0; i < N; i++) { pkg = packagesToBackup.get(i); - backupOnePackage(pkg); + backupOnePackage(pkg, out); } // Finally, shared storage if requested @@ -1754,6 +1817,7 @@ class BackupManagerService extends IBackupManager.Stub { } finally { tearDown(pkg); try { + out.close(); mOutputFile.close(); } catch (IOException e) { /* nothing we can do about this */ @@ -1771,13 +1835,17 @@ class BackupManagerService extends IBackupManager.Stub { } } - private void backupOnePackage(PackageInfo pkg) throws RemoteException { + private void backupOnePackage(PackageInfo pkg, DeflaterOutputStream out) + throws RemoteException { Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName); IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo, IApplicationThread.BACKUP_MODE_FULL); if (agent != null) { + ParcelFileDescriptor[] pipes = null; try { + pipes = ParcelFileDescriptor.createPipe(); + ApplicationInfo app = pkg.applicationInfo; final boolean sendApk = mIncludeApks && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0) @@ -1786,31 +1854,54 @@ class BackupManagerService extends IBackupManager.Stub { sendOnBackupPackage(pkg.packageName); - BackupDataOutput output = new BackupDataOutput( - mOutputFile.getFileDescriptor()); - - if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName); - writeAppManifest(pkg, mManifestFile, sendApk); - FullBackup.backupToTar(pkg.packageName, null, null, - mFilesDir.getAbsolutePath(), - mManifestFile.getAbsolutePath(), - output); - - if (sendApk) { - writeApkToBackup(pkg, output); + final int token = generateToken(); + FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1], + token, sendApk); + pipes[1].close(); // the runner has dup'd it + pipes[1] = null; + Thread t = new Thread(runner); + t.start(); + + // Now pull data from the app and stuff it into the compressor + try { + FileInputStream raw = new FileInputStream(pipes[0].getFileDescriptor()); + DataInputStream in = new DataInputStream(raw); + + byte[] buffer = new byte[16 * 1024]; + int chunkTotal; + while ((chunkTotal = in.readInt()) > 0) { + while (chunkTotal > 0) { + int toRead = (chunkTotal > buffer.length) + ? buffer.length : chunkTotal; + int nRead = in.read(buffer, 0, toRead); + out.write(buffer, 0, nRead); + chunkTotal -= nRead; + } + } + } catch (IOException e) { + Slog.i(TAG, "Caught exception reading from agent", e); } - if (DEBUG) Slog.d(TAG, "Calling doFullBackup()"); - final int token = generateToken(); - prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL); - agent.doFullBackup(mOutputFile, token, mBackupManagerBinder); if (!waitUntilOperationComplete(token)) { Slog.e(TAG, "Full backup failed on package " + pkg.packageName); } else { - if (DEBUG) Slog.d(TAG, "Full backup success: " + pkg.packageName); + if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName); } + } catch (IOException e) { Slog.e(TAG, "Error backing up " + pkg.packageName, e); + } finally { + try { + if (pipes != null) { + if (pipes[0] != null) pipes[0].close(); + if (pipes[1] != null) pipes[1].close(); + } + + // Apply a full sync/flush after each application's data + out.flush(); + } catch (IOException e) { + Slog.w(TAG, "Error bringing down backup stack"); + } } } else { Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName); @@ -2084,11 +2175,12 @@ class BackupManagerService extends IBackupManager.Stub { try { mBytes = 0; byte[] buffer = new byte[32 * 1024]; - FileInputStream instream = new FileInputStream(mInputFile.getFileDescriptor()); + FileInputStream rawInStream = new FileInputStream(mInputFile.getFileDescriptor()); + InflaterInputStream in = new InflaterInputStream(rawInStream); boolean didRestore; do { - didRestore = restoreOneFile(instream, buffer); + didRestore = restoreOneFile(in, buffer); } while (didRestore); if (DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes); diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 2e54c99..94465fd 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -2361,6 +2361,19 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC pw.print(" -> "); pw.println(e.getValue().toString()); } } + + pw.println(""); + + synchronized (mVolumes) { + pw.println(" mVolumes:"); + + final int N = mVolumes.size(); + for (int i = 0; i < N; i++) { + final StorageVolume v = mVolumes.get(i); + pw.print(" "); + pw.println(v.toString()); + } + } } } diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 829df39..41e8a31 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -196,6 +196,9 @@ class NetworkManagementService extends INetworkManagementService.Stub { } else { Slog.d(TAG, "not enabling bandwidth control"); } + + SystemProperties.set(NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED, + mBandwidthControlEnabled ? "1" : "0"); } public void registerObserver(INetworkManagementEventObserver obs) { diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index 80cdf6b..f99951fa 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1155,9 +1155,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION; private static final int RETRIEVAL_ALLOWING_EVENT_TYPES = - AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END - | AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START - | AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED + AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_SELECTED diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java index 1af7015..dbd9474 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -838,8 +838,6 @@ public class TouchExplorer implements Explorer { */ private void sendAccessibilityEvent(int eventType) { AccessibilityEvent event = AccessibilityEvent.obtain(eventType); - event.setPackageName(mContext.getPackageName()); - event.setClassName(getClass().getName()); mAccessibilityManager.sendAccessibilityEvent(event); } diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java index d3d9df4..bfa2b39 100644 --- a/services/java/com/android/server/wm/AppWindowToken.java +++ b/services/java/com/android/server/wm/AppWindowToken.java @@ -101,7 +101,7 @@ class AppWindowToken extends WindowToken { boolean firstWindowDrawn; // Input application handle used by the input dispatcher. - InputApplicationHandle mInputApplicationHandle; + final InputApplicationHandle mInputApplicationHandle; AppWindowToken(WindowManagerService _service, IApplicationToken _token) { super(_service, _token.asBinder(), diff --git a/services/java/com/android/server/wm/InputApplication.java b/services/java/com/android/server/wm/InputApplication.java deleted file mode 100644 index e04fd31..0000000 --- a/services/java/com/android/server/wm/InputApplication.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - - -/** - * Describes input-related application properties for use by the input dispatcher. - * @hide - */ -public final class InputApplication { - // Application handle. - public InputApplicationHandle inputApplicationHandle; - - // Application name. - public String name; - - // Dispatching timeout. - public long dispatchingTimeoutNanos; - - public void recycle() { - inputApplicationHandle = null; - } -} diff --git a/services/java/com/android/server/wm/InputApplicationHandle.java b/services/java/com/android/server/wm/InputApplicationHandle.java index 64c8e7e..d78b1d9 100644 --- a/services/java/com/android/server/wm/InputApplicationHandle.java +++ b/services/java/com/android/server/wm/InputApplicationHandle.java @@ -32,6 +32,12 @@ public final class InputApplicationHandle { // The window manager's application window token. public final AppWindowToken appWindowToken; + // Application name. + public String name; + + // Dispatching timeout. + public long dispatchingTimeoutNanos; + private native void nativeDispose(); public InputApplicationHandle(AppWindowToken appWindowToken) { diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java index 65007f9..3133a19 100644 --- a/services/java/com/android/server/wm/InputManager.java +++ b/services/java/com/android/server/wm/InputManager.java @@ -25,7 +25,6 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.ContentObserver; import android.os.Environment; -import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; import android.os.SystemProperties; @@ -83,10 +82,10 @@ public class InputManager { private static native int nativeInjectInputEvent(InputEvent event, int injectorPid, int injectorUid, int syncMode, int timeoutMillis, int policyFlags); - private static native void nativeSetInputWindows(InputWindow[] windows); + private static native void nativeSetInputWindows(InputWindowHandle[] windowHandles); private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen); private static native void nativeSetSystemUiVisibility(int visibility); - private static native void nativeSetFocusedApplication(InputApplication application); + private static native void nativeSetFocusedApplication(InputApplicationHandle application); private static native InputDevice nativeGetInputDevice(int deviceId); private static native void nativeGetInputConfiguration(Configuration configuration); private static native int[] nativeGetInputDeviceIds(); @@ -372,11 +371,11 @@ public class InputManager { return nativeGetInputDeviceIds(); } - public void setInputWindows(InputWindow[] windows) { - nativeSetInputWindows(windows); + public void setInputWindows(InputWindowHandle[] windowHandles) { + nativeSetInputWindows(windowHandles); } - public void setFocusedApplication(InputApplication application) { + public void setFocusedApplication(InputApplicationHandle application) { nativeSetFocusedApplication(application); } diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java index 6806634..08a3560 100644 --- a/services/java/com/android/server/wm/InputMonitor.java +++ b/services/java/com/android/server/wm/InputMonitor.java @@ -17,7 +17,6 @@ package com.android.server.wm; import android.graphics.Rect; -import android.os.Binder; import android.os.Process; import android.os.RemoteException; import android.util.Log; @@ -26,6 +25,7 @@ import android.view.KeyEvent; import android.view.WindowManager; import java.util.ArrayList; +import java.util.Arrays; final class InputMonitor { private final WindowManagerService mService; @@ -42,12 +42,14 @@ final class InputMonitor { // When true, need to call updateInputWindowsLw(). private boolean mUpdateInputWindowsNeeded = true; - // Temporary list of windows information to provide to the input dispatcher. - private InputWindowList mTempInputWindows = new InputWindowList(); - - // Temporary input application object to provide to the input dispatcher. - private InputApplication mTempInputApplication = new InputApplication(); - + // Fake handles for the drag surface, lazily initialized. + private InputApplicationHandle mDragApplicationHandle; + private InputWindowHandle mDragWindowHandle; + + // Array of window handles to provide to the input dispatcher. + private InputWindowHandle[] mInputWindowHandles; + private int mInputWindowHandleCount; + // Set to true when the first input device configuration change notification // is received to indicate that the input devices are ready. private final Object mInputDevicesReadyMonitor = new Object(); @@ -68,8 +70,10 @@ final class InputMonitor { synchronized (mService.mWindowMap) { WindowState windowState = (WindowState) inputWindowHandle.windowState; - Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState); - mService.removeWindowLocked(windowState.mSession, windowState); + if (windowState != null) { + Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState); + mService.removeWindowLocked(windowState.mSession, windowState); + } } } @@ -94,8 +98,11 @@ final class InputMonitor { if (appWindowToken == null && inputApplicationHandle != null) { appWindowToken = inputApplicationHandle.appWindowToken; - Slog.i(WindowManagerService.TAG, "Input event dispatching timed out sending to application " - + appWindowToken.stringName); + if (appWindowToken != null) { + Slog.i(WindowManagerService.TAG, + "Input event dispatching timed out sending to application " + + appWindowToken.stringName); + } } if (appWindowToken != null && appWindowToken.appToken != null) { @@ -114,32 +121,59 @@ final class InputMonitor { return 0; // abort dispatching } - private void addDragInputWindowLw(InputWindowList windowList) { - final InputWindow inputWindow = windowList.add(); - inputWindow.inputChannel = mService.mDragState.mServerChannel; - inputWindow.name = "drag"; - inputWindow.layoutParamsFlags = 0; - inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG; - inputWindow.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; - inputWindow.visible = true; - inputWindow.canReceiveKeys = false; - inputWindow.hasFocus = true; - inputWindow.hasWallpaper = false; - inputWindow.paused = false; - inputWindow.layer = mService.mDragState.getDragLayerLw(); - inputWindow.ownerPid = Process.myPid(); - inputWindow.ownerUid = Process.myUid(); - inputWindow.inputFeatures = 0; - inputWindow.scaleFactor = 1.0f; + private void addDragInputWindowLw() { + if (mDragWindowHandle == null) { + mDragApplicationHandle = new InputApplicationHandle(null); + mDragApplicationHandle.name = "drag"; + mDragApplicationHandle.dispatchingTimeoutNanos = + WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; + + mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null); + mDragWindowHandle.name = "drag"; + mDragWindowHandle.layoutParamsFlags = 0; + mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG; + mDragWindowHandle.dispatchingTimeoutNanos = + WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; + mDragWindowHandle.visible = true; + mDragWindowHandle.canReceiveKeys = false; + mDragWindowHandle.hasFocus = true; + mDragWindowHandle.hasWallpaper = false; + mDragWindowHandle.paused = false; + mDragWindowHandle.ownerPid = Process.myPid(); + mDragWindowHandle.ownerUid = Process.myUid(); + mDragWindowHandle.inputFeatures = 0; + mDragWindowHandle.scaleFactor = 1.0f; + + // The drag window cannot receive new touches. + mDragWindowHandle.touchableRegion.setEmpty(); + } + + mDragWindowHandle.layer = mService.mDragState.getDragLayerLw(); // The drag window covers the entire display - inputWindow.frameLeft = 0; - inputWindow.frameTop = 0; - inputWindow.frameRight = mService.mDisplay.getRealWidth(); - inputWindow.frameBottom = mService.mDisplay.getRealHeight(); + mDragWindowHandle.frameLeft = 0; + mDragWindowHandle.frameTop = 0; + mDragWindowHandle.frameRight = mService.mDisplay.getRealWidth(); + mDragWindowHandle.frameBottom = mService.mDisplay.getRealHeight(); + + addInputWindowHandleLw(mDragWindowHandle); + } - // The drag window cannot receive new touches. - inputWindow.touchableRegion.setEmpty(); + private void addInputWindowHandleLw(InputWindowHandle windowHandle) { + if (mInputWindowHandles == null) { + mInputWindowHandles = new InputWindowHandle[16]; + } + if (mInputWindowHandleCount >= mInputWindowHandles.length) { + mInputWindowHandles = Arrays.copyOf(mInputWindowHandles, + mInputWindowHandleCount * 2); + } + mInputWindowHandles[mInputWindowHandleCount++] = windowHandle; + } + + private void clearInputWindowHandlesLw() { + while (mInputWindowHandleCount != 0) { + mInputWindowHandles[--mInputWindowHandleCount] = null; + } } public void setUpdateInputWindowsNeededLw() { @@ -154,7 +188,7 @@ final class InputMonitor { mUpdateInputWindowsNeeded = false; if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED updateInputWindowsLw"); - + // Populate the input window list with information about all of the windows that // could potentially receive input. // As an optimization, we could try to prune the list of windows but this turns @@ -168,7 +202,7 @@ final class InputMonitor { if (WindowManagerService.DEBUG_DRAG) { Log.d(WindowManagerService.TAG, "Inserting drag window"); } - addDragInputWindowLw(mTempInputWindows); + addDragInputWindowLw(); } final int N = windows.size(); @@ -194,48 +228,48 @@ final class InputMonitor { } // Add a window to our list of input windows. - final InputWindow inputWindow = mTempInputWindows.add(); - inputWindow.inputWindowHandle = child.mInputWindowHandle; - inputWindow.inputChannel = child.mInputChannel; - inputWindow.name = child.toString(); - inputWindow.layoutParamsFlags = flags; - inputWindow.layoutParamsType = type; - inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos(); - inputWindow.visible = isVisible; - inputWindow.canReceiveKeys = child.canReceiveKeys(); - inputWindow.hasFocus = hasFocus; - inputWindow.hasWallpaper = hasWallpaper; - inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false; - inputWindow.layer = child.mLayer; - inputWindow.ownerPid = child.mSession.mPid; - inputWindow.ownerUid = child.mSession.mUid; - inputWindow.inputFeatures = child.mAttrs.inputFeatures; + final InputWindowHandle inputWindowHandle = child.mInputWindowHandle; + inputWindowHandle.inputChannel = child.mInputChannel; + inputWindowHandle.name = child.toString(); + inputWindowHandle.layoutParamsFlags = flags; + inputWindowHandle.layoutParamsType = type; + inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos(); + inputWindowHandle.visible = isVisible; + inputWindowHandle.canReceiveKeys = child.canReceiveKeys(); + inputWindowHandle.hasFocus = hasFocus; + inputWindowHandle.hasWallpaper = hasWallpaper; + inputWindowHandle.paused = child.mAppToken != null ? child.mAppToken.paused : false; + inputWindowHandle.layer = child.mLayer; + inputWindowHandle.ownerPid = child.mSession.mPid; + inputWindowHandle.ownerUid = child.mSession.mUid; + inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures; final Rect frame = child.mFrame; - inputWindow.frameLeft = frame.left; - inputWindow.frameTop = frame.top; - inputWindow.frameRight = frame.right; - inputWindow.frameBottom = frame.bottom; + inputWindowHandle.frameLeft = frame.left; + inputWindowHandle.frameTop = frame.top; + inputWindowHandle.frameRight = frame.right; + inputWindowHandle.frameBottom = frame.bottom; if (child.mGlobalScale != 1) { // If we are scaling the window, input coordinates need // to be inversely scaled to map from what is on screen // to what is actually being touched in the UI. - inputWindow.scaleFactor = 1.0f/child.mGlobalScale; + inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale; } else { - inputWindow.scaleFactor = 1; + inputWindowHandle.scaleFactor = 1; } - child.getTouchableRegion(inputWindow.touchableRegion); + child.getTouchableRegion(inputWindowHandle.touchableRegion); + + addInputWindowHandleLw(inputWindowHandle); } // Send windows to native code. - mService.mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray()); - + mService.mInputManager.setInputWindows(mInputWindowHandles); + // Clear the list in preparation for the next round. - // Also avoids keeping InputChannel objects referenced unnecessarily. - mTempInputWindows.clear(); - + clearInputWindowHandlesLw(); + if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw"); } @@ -329,14 +363,11 @@ final class InputMonitor { if (newApp == null) { mService.mInputManager.setFocusedApplication(null); } else { - mTempInputApplication.inputApplicationHandle = newApp.mInputApplicationHandle; - mTempInputApplication.name = newApp.toString(); - mTempInputApplication.dispatchingTimeoutNanos = - newApp.inputDispatchingTimeoutNanos; - - mService.mInputManager.setFocusedApplication(mTempInputApplication); + final InputApplicationHandle handle = newApp.mInputApplicationHandle; + handle.name = newApp.toString(); + handle.dispatchingTimeoutNanos = newApp.inputDispatchingTimeoutNanos; - mTempInputApplication.recycle(); + mService.mInputManager.setFocusedApplication(handle); } } diff --git a/services/java/com/android/server/wm/InputWindow.java b/services/java/com/android/server/wm/InputWindow.java deleted file mode 100644 index 655d734..0000000 --- a/services/java/com/android/server/wm/InputWindow.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -import android.graphics.Region; -import android.view.InputChannel; - -/** - * Describes input-related window properties for use by the input dispatcher. - * @hide - */ -public final class InputWindow { - // The window handle. - public InputWindowHandle inputWindowHandle; - - // The input channel associated with the window. - public InputChannel inputChannel; - - // The window name. - public String name; - - // Window layout params attributes. (WindowManager.LayoutParams) - public int layoutParamsFlags; - public int layoutParamsType; - - // Dispatching timeout. - public long dispatchingTimeoutNanos; - - // Window frame. - public int frameLeft; - public int frameTop; - public int frameRight; - public int frameBottom; - - // Global scaling factor applied to touch events when they are dispatched - // to the window - public float scaleFactor; - - // Window touchable region. - public final Region touchableRegion = new Region(); - - // Window is visible. - public boolean visible; - - // Window can receive keys. - public boolean canReceiveKeys; - - // Window has focus. - public boolean hasFocus; - - // Window has wallpaper. (window is the current wallpaper target) - public boolean hasWallpaper; - - // Input event dispatching is paused. - public boolean paused; - - // Window layer. - public int layer; - - // Id of process and user that owns the window. - public int ownerPid; - public int ownerUid; - - // Window input features. - public int inputFeatures; - - public void recycle() { - inputWindowHandle = null; - inputChannel = null; - } -} diff --git a/services/java/com/android/server/wm/InputWindowHandle.java b/services/java/com/android/server/wm/InputWindowHandle.java index cc508c6..abf68d9 100644 --- a/services/java/com/android/server/wm/InputWindowHandle.java +++ b/services/java/com/android/server/wm/InputWindowHandle.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import android.graphics.Region; +import android.view.InputChannel; import android.view.WindowManagerPolicy; /** @@ -35,6 +37,57 @@ public final class InputWindowHandle { // The window manager's window state. public final WindowManagerPolicy.WindowState windowState; + // The input channel associated with the window. + public InputChannel inputChannel; + + // The window name. + public String name; + + // Window layout params attributes. (WindowManager.LayoutParams) + public int layoutParamsFlags; + public int layoutParamsType; + + // Dispatching timeout. + public long dispatchingTimeoutNanos; + + // Window frame. + public int frameLeft; + public int frameTop; + public int frameRight; + public int frameBottom; + + // Global scaling factor applied to touch events when they are dispatched + // to the window + public float scaleFactor; + + // Window touchable region. + public final Region touchableRegion = new Region(); + + // Window is visible. + public boolean visible; + + // Window can receive keys. + public boolean canReceiveKeys; + + // Window has focus. + public boolean hasFocus; + + // Window has wallpaper. (window is the current wallpaper target) + public boolean hasWallpaper; + + // Input event dispatching is paused. + public boolean paused; + + // Window layer. + public int layer; + + // Id of process and user that owns the window. + public int ownerPid; + public int ownerUid; + + // Window input features. + public int inputFeatures; + private native void nativeDispose(); public InputWindowHandle(InputApplicationHandle inputApplicationHandle, diff --git a/services/java/com/android/server/wm/InputWindowList.java b/services/java/com/android/server/wm/InputWindowList.java deleted file mode 100644 index 6077337..0000000 --- a/services/java/com/android/server/wm/InputWindowList.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - - -/** - * A specialized list of window information objects backed by an array. - * - * This class is part of an InputManager optimization to avoid allocating objects and arrays - * unnecessarily. Internally, it keeps an array full of demand-allocated objects that it - * recycles each time the list is cleared. The used portion of the array is padded with a null. - * - * The contents of the list are intended to be Z-ordered from top to bottom. - * - * @hide - */ -public final class InputWindowList { - private InputWindow[] mArray; - private int mCount; - - /** - * Creates an empty list. - */ - public InputWindowList() { - mArray = new InputWindow[8]; - } - - /** - * Clears the list. - */ - public void clear() { - if (mCount == 0) { - return; - } - - int count = mCount; - mCount = 0; - mArray[count] = mArray[0]; - while (count > 0) { - count -= 1; - mArray[count].recycle(); - } - mArray[0] = null; - } - - /** - * Adds an uninitialized input window object to the list and returns it. - */ - public InputWindow add() { - if (mCount + 1 == mArray.length) { - InputWindow[] oldArray = mArray; - mArray = new InputWindow[oldArray.length * 2]; - System.arraycopy(oldArray, 0, mArray, 0, mCount); - } - - // Grab object from tail (after used section) if available. - InputWindow item = mArray[mCount + 1]; - if (item == null) { - item = new InputWindow(); - } - - mArray[mCount] = item; - mCount += 1; - mArray[mCount] = null; - return item; - } - - /** - * Gets the input window objects as a null-terminated array. - * @return The input window array. - */ - public InputWindow[] toNullTerminatedArray() { - return mArray; - } -}
\ No newline at end of file diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index b370ec9..d298ff7 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -272,7 +272,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { float mSurfaceAlpha; // Input channel and input window handle used by the input dispatcher. - InputWindowHandle mInputWindowHandle; + final InputWindowHandle mInputWindowHandle; InputChannel mInputChannel; // Used to improve performance of toString() @@ -306,6 +306,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mIsFloatingLayer = false; mBaseLayer = 0; mSubLayer = 0; + mInputWindowHandle = null; return; } mDeathRecipient = deathRecipient; diff --git a/services/jni/Android.mk b/services/jni/Android.mk index e1c7305..6fa5dfa 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -4,10 +4,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ com_android_server_AlarmManagerService.cpp \ com_android_server_BatteryService.cpp \ - com_android_server_InputApplication.cpp \ com_android_server_InputApplicationHandle.cpp \ com_android_server_InputManager.cpp \ - com_android_server_InputWindow.cpp \ com_android_server_InputWindowHandle.cpp \ com_android_server_LightsService.cpp \ com_android_server_PowerManagerService.cpp \ diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp index c9a702a..e80dd04 100644 --- a/services/jni/com_android_server_AlarmManagerService.cpp +++ b/services/jni/com_android_server_AlarmManagerService.cpp @@ -32,17 +32,13 @@ #include <stdlib.h> #include <errno.h> #include <unistd.h> - -#ifdef HAVE_ANDROID_OS #include <linux/ioctl.h> #include <linux/android_alarm.h> -#endif namespace android { static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest) { -#ifdef HAVE_ANDROID_OS struct timezone tz; tz.tz_minuteswest = minswest; @@ -57,30 +53,20 @@ static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jo } return 0; -#else - return -ENOSYS; -#endif } static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj) { -#ifdef HAVE_ANDROID_OS return open("/dev/alarm", O_RDWR); -#else - return -1; -#endif } static void android_server_AlarmManagerService_close(JNIEnv* env, jobject obj, jint fd) { -#ifdef HAVE_ANDROID_OS close(fd); -#endif } static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds) { -#ifdef HAVE_ANDROID_OS struct timespec ts; ts.tv_sec = seconds; ts.tv_nsec = nanoseconds; @@ -90,12 +76,10 @@ static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jin { LOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno)); } -#endif } static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd) { -#ifdef HAVE_ANDROID_OS int result = 0; do @@ -110,7 +94,6 @@ static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject } return result; -#endif } static JNINativeMethod sMethods[] = { diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp index 98d0d92..b9f2c1f 100644 --- a/services/jni/com_android_server_BatteryService.cpp +++ b/services/jni/com_android_server_BatteryService.cpp @@ -32,10 +32,7 @@ #include <errno.h> #include <unistd.h> #include <dirent.h> - -#ifdef HAVE_ANDROID_OS #include <linux/ioctl.h> -#endif namespace android { diff --git a/services/jni/com_android_server_InputApplication.cpp b/services/jni/com_android_server_InputApplication.cpp deleted file mode 100644 index 1f80242..0000000 --- a/services/jni/com_android_server_InputApplication.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "InputApplication" - -#include "JNIHelp.h" -#include "jni.h" -#include <android_runtime/AndroidRuntime.h> - -#include "com_android_server_InputApplication.h" -#include "com_android_server_InputApplicationHandle.h" - -namespace android { - -static struct { - jfieldID inputApplicationHandle; - jfieldID name; - jfieldID dispatchingTimeoutNanos; -} gInputApplicationClassInfo; - - -// --- Global functions --- - -void android_server_InputApplication_toNative( - JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication) { - jobject inputApplicationHandleObj = env->GetObjectField(inputApplicationObj, - gInputApplicationClassInfo.inputApplicationHandle); - if (inputApplicationHandleObj) { - outInputApplication->inputApplicationHandle = - android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj); - env->DeleteLocalRef(inputApplicationHandleObj); - } else { - outInputApplication->inputApplicationHandle = NULL; - } - - jstring nameObj = jstring(env->GetObjectField(inputApplicationObj, - gInputApplicationClassInfo.name)); - if (nameObj) { - const char* nameStr = env->GetStringUTFChars(nameObj, NULL); - outInputApplication->name.setTo(nameStr); - env->ReleaseStringUTFChars(nameObj, nameStr); - env->DeleteLocalRef(nameObj); - } else { - LOGE("InputApplication.name should not be null."); - outInputApplication->name.setTo("unknown"); - } - - outInputApplication->dispatchingTimeout = env->GetLongField(inputApplicationObj, - gInputApplicationClassInfo.dispatchingTimeoutNanos); -} - - -// --- JNI --- - -#define FIND_CLASS(var, className) \ - var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); - -#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ - var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ - LOG_FATAL_IF(! var, "Unable to find field " fieldName); - -int register_android_server_InputApplication(JNIEnv* env) { - jclass clazz; - FIND_CLASS(clazz, "com/android/server/wm/InputApplication"); - - GET_FIELD_ID(gInputApplicationClassInfo.inputApplicationHandle, - clazz, - "inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;"); - - GET_FIELD_ID(gInputApplicationClassInfo.name, clazz, - "name", "Ljava/lang/String;"); - - GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos, - clazz, - "dispatchingTimeoutNanos", "J"); - return 0; -} - -} /* namespace android */ diff --git a/services/jni/com_android_server_InputApplication.h b/services/jni/com_android_server_InputApplication.h deleted file mode 100644 index 85fb891..0000000 --- a/services/jni/com_android_server_InputApplication.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _ANDROID_SERVER_INPUT_APPLICATION_H -#define _ANDROID_SERVER_INPUT_APPLICATION_H - -#include <input/InputApplication.h> - -#include "JNIHelp.h" -#include "jni.h" - -namespace android { - -extern void android_server_InputApplication_toNative( - JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication); - -} // namespace android - -#endif // _ANDROID_SERVER_INPUT_APPLICATION_H diff --git a/services/jni/com_android_server_InputApplicationHandle.cpp b/services/jni/com_android_server_InputApplicationHandle.cpp index 9516964..7de67d9 100644 --- a/services/jni/com_android_server_InputApplicationHandle.cpp +++ b/services/jni/com_android_server_InputApplicationHandle.cpp @@ -27,6 +27,8 @@ namespace android { static struct { jfieldID ptr; + jfieldID name; + jfieldID dispatchingTimeoutNanos; } gInputApplicationHandleClassInfo; static Mutex gHandleMutex; @@ -47,6 +49,31 @@ jobject NativeInputApplicationHandle::getInputApplicationHandleObjLocalRef(JNIEn return env->NewLocalRef(mObjWeak); } +bool NativeInputApplicationHandle::update() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jobject obj = env->NewLocalRef(mObjWeak); + if (!obj) { + return false; + } + + jstring nameObj = jstring(env->GetObjectField(obj, + gInputApplicationHandleClassInfo.name)); + if (nameObj) { + const char* nameStr = env->GetStringUTFChars(nameObj, NULL); + name.setTo(nameStr); + env->ReleaseStringUTFChars(nameObj, nameStr); + env->DeleteLocalRef(nameObj); + } else { + name.setTo("<null>"); + } + + dispatchingTimeout = env->GetLongField(obj, + gInputApplicationHandleClassInfo.dispatchingTimeoutNanos); + + env->DeleteLocalRef(obj); + return true; +} + // --- Global functions --- @@ -113,6 +140,13 @@ int register_android_server_InputApplicationHandle(JNIEnv* env) { GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz, "ptr", "I"); + GET_FIELD_ID(gInputApplicationHandleClassInfo.name, clazz, + "name", "Ljava/lang/String;"); + + GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutNanos, + clazz, + "dispatchingTimeoutNanos", "J"); + return 0; } diff --git a/services/jni/com_android_server_InputApplicationHandle.h b/services/jni/com_android_server_InputApplicationHandle.h index 9d18721..04cd9d6 100644 --- a/services/jni/com_android_server_InputApplicationHandle.h +++ b/services/jni/com_android_server_InputApplicationHandle.h @@ -31,6 +31,8 @@ public: jobject getInputApplicationHandleObjLocalRef(JNIEnv* env); + virtual bool update(); + private: jweak mObjWeak; }; diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 14a4109..de9c9d0 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -46,9 +46,7 @@ #include <android/graphics/GraphicsJNI.h> #include "com_android_server_PowerManagerService.h" -#include "com_android_server_InputApplication.h" #include "com_android_server_InputApplicationHandle.h" -#include "com_android_server_InputWindow.h" #include "com_android_server_InputWindowHandle.h" namespace android { @@ -175,8 +173,8 @@ public: const sp<InputWindowHandle>& inputWindowHandle, bool monitor); status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel); - void setInputWindows(JNIEnv* env, jobjectArray windowObjArray); - void setFocusedApplication(JNIEnv* env, jobject applicationObj); + void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray); + void setFocusedApplication(JNIEnv* env, jobject applicationHandleObj); void setInputDispatchMode(bool enabled, bool frozen); void setSystemUiVisibility(int32_t visibility); void setPointerSpeed(int32_t speed); @@ -582,31 +580,38 @@ bool NativeInputManager::isKeyRepeatEnabled() { return isScreenOn(); } -void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArray) { - Vector<InputWindow> windows; +void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) { + Vector<sp<InputWindowHandle> > windowHandles; - bool newPointerGesturesEnabled = true; - jsize length = env->GetArrayLength(windowObjArray); - for (jsize i = 0; i < length; i++) { - jobject windowObj = env->GetObjectArrayElement(windowObjArray, i); - if (! windowObj) { - break; // found null element indicating end of used portion of the array - } + if (windowHandleObjArray) { + jsize length = env->GetArrayLength(windowHandleObjArray); + for (jsize i = 0; i < length; i++) { + jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i); + if (! windowHandleObj) { + break; // found null element indicating end of used portion of the array + } - windows.push(); - InputWindow& window = windows.editTop(); - android_server_InputWindow_toNative(env, windowObj, &window); - if (window.inputChannel == NULL) { - windows.pop(); - } else if (window.hasFocus) { - if (window.inputFeatures & InputWindow::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES) { - newPointerGesturesEnabled = false; + sp<InputWindowHandle> windowHandle = + android_server_InputWindowHandle_getHandle(env, windowHandleObj); + if (windowHandle != NULL) { + windowHandles.push(windowHandle); } + env->DeleteLocalRef(windowHandleObj); } - env->DeleteLocalRef(windowObj); } - mInputManager->getDispatcher()->setInputWindows(windows); + mInputManager->getDispatcher()->setInputWindows(windowHandles); + + // Do this after the dispatcher has updated the window handle state. + bool newPointerGesturesEnabled = true; + size_t numWindows = windowHandles.size(); + for (size_t i = 0; i < numWindows; i++) { + const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i); + if (windowHandle->hasFocus && (windowHandle->inputFeatures + & InputWindowHandle::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) { + newPointerGesturesEnabled = false; + } + } uint32_t changes = 0; { // acquire lock @@ -623,16 +628,10 @@ void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArra } } -void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationObj) { - if (applicationObj) { - InputApplication application; - android_server_InputApplication_toNative(env, applicationObj, &application); - if (application.inputApplicationHandle != NULL) { - mInputManager->getDispatcher()->setFocusedApplication(&application); - return; - } - } - mInputManager->getDispatcher()->setFocusedApplication(NULL); +void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationHandleObj) { + sp<InputApplicationHandle> applicationHandle = + android_server_InputApplicationHandle_getHandle(env, applicationHandleObj); + mInputManager->getDispatcher()->setFocusedApplication(applicationHandle); } void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) { @@ -1137,21 +1136,21 @@ static jint android_server_InputManager_nativeInjectInputEvent(JNIEnv* env, jcla } static void android_server_InputManager_nativeSetInputWindows(JNIEnv* env, jclass clazz, - jobjectArray windowObjArray) { + jobjectArray windowHandleObjArray) { if (checkInputManagerUnitialized(env)) { return; } - gNativeInputManager->setInputWindows(env, windowObjArray); + gNativeInputManager->setInputWindows(env, windowHandleObjArray); } static void android_server_InputManager_nativeSetFocusedApplication(JNIEnv* env, jclass clazz, - jobject applicationObj) { + jobject applicationHandleObj) { if (checkInputManagerUnitialized(env)) { return; } - gNativeInputManager->setFocusedApplication(env, applicationObj); + gNativeInputManager->setFocusedApplication(env, applicationHandleObj); } static void android_server_InputManager_nativeSetInputDispatchMode(JNIEnv* env, @@ -1313,9 +1312,9 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) android_server_InputManager_nativeSetInputFilterEnabled }, { "nativeInjectInputEvent", "(Landroid/view/InputEvent;IIIII)I", (void*) android_server_InputManager_nativeInjectInputEvent }, - { "nativeSetInputWindows", "([Lcom/android/server/wm/InputWindow;)V", + { "nativeSetInputWindows", "([Lcom/android/server/wm/InputWindowHandle;)V", (void*) android_server_InputManager_nativeSetInputWindows }, - { "nativeSetFocusedApplication", "(Lcom/android/server/wm/InputApplication;)V", + { "nativeSetFocusedApplication", "(Lcom/android/server/wm/InputApplicationHandle;)V", (void*) android_server_InputManager_nativeSetFocusedApplication }, { "nativeSetInputDispatchMode", "(ZZ)V", (void*) android_server_InputManager_nativeSetInputDispatchMode }, diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp deleted file mode 100644 index 0426f63..0000000 --- a/services/jni/com_android_server_InputWindow.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "InputWindow" - -#include "JNIHelp.h" -#include "jni.h" -#include <android_runtime/AndroidRuntime.h> - -#include <android_view_InputChannel.h> -#include <android/graphics/Region.h> -#include "com_android_server_InputWindow.h" -#include "com_android_server_InputWindowHandle.h" - -namespace android { - -static struct { - jfieldID inputWindowHandle; - jfieldID inputChannel; - jfieldID name; - jfieldID layoutParamsFlags; - jfieldID layoutParamsType; - jfieldID dispatchingTimeoutNanos; - jfieldID frameLeft; - jfieldID frameTop; - jfieldID frameRight; - jfieldID frameBottom; - jfieldID scaleFactor; - jfieldID touchableRegion; - jfieldID visible; - jfieldID canReceiveKeys; - jfieldID hasFocus; - jfieldID hasWallpaper; - jfieldID paused; - jfieldID layer; - jfieldID ownerPid; - jfieldID ownerUid; - jfieldID inputFeatures; -} gInputWindowClassInfo; - - -// --- Global functions --- - -void android_server_InputWindow_toNative( - JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow) { - jobject inputWindowHandleObj = env->GetObjectField(inputWindowObj, - gInputWindowClassInfo.inputWindowHandle); - if (inputWindowHandleObj) { - outInputWindow->inputWindowHandle = - android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj); - env->DeleteLocalRef(inputWindowHandleObj); - } else { - outInputWindow->inputWindowHandle = NULL; - } - - jobject inputChannelObj = env->GetObjectField(inputWindowObj, - gInputWindowClassInfo.inputChannel); - if (inputChannelObj) { - outInputWindow->inputChannel = - android_view_InputChannel_getInputChannel(env, inputChannelObj); - env->DeleteLocalRef(inputChannelObj); - } else { - outInputWindow->inputChannel = NULL; - } - - jstring nameObj = jstring(env->GetObjectField(inputWindowObj, - gInputWindowClassInfo.name)); - if (nameObj) { - const char* nameStr = env->GetStringUTFChars(nameObj, NULL); - outInputWindow->name.setTo(nameStr); - env->ReleaseStringUTFChars(nameObj, nameStr); - env->DeleteLocalRef(nameObj); - } else { - LOGE("InputWindow.name should not be null."); - outInputWindow->name.setTo("unknown"); - } - - outInputWindow->layoutParamsFlags = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.layoutParamsFlags); - outInputWindow->layoutParamsType = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.layoutParamsType); - outInputWindow->dispatchingTimeout = env->GetLongField(inputWindowObj, - gInputWindowClassInfo.dispatchingTimeoutNanos); - outInputWindow->frameLeft = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.frameLeft); - outInputWindow->frameTop = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.frameTop); - outInputWindow->frameRight = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.frameRight); - outInputWindow->frameBottom = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.frameBottom); - outInputWindow->scaleFactor = env->GetFloatField(inputWindowObj, - gInputWindowClassInfo.scaleFactor); - - jobject regionObj = env->GetObjectField(inputWindowObj, - gInputWindowClassInfo.touchableRegion); - if (regionObj) { - SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj); - outInputWindow->touchableRegion.set(*region); - env->DeleteLocalRef(regionObj); - } else { - outInputWindow->touchableRegion.setEmpty(); - } - - outInputWindow->visible = env->GetBooleanField(inputWindowObj, - gInputWindowClassInfo.visible); - outInputWindow->canReceiveKeys = env->GetBooleanField(inputWindowObj, - gInputWindowClassInfo.canReceiveKeys); - outInputWindow->hasFocus = env->GetBooleanField(inputWindowObj, - gInputWindowClassInfo.hasFocus); - outInputWindow->hasWallpaper = env->GetBooleanField(inputWindowObj, - gInputWindowClassInfo.hasWallpaper); - outInputWindow->paused = env->GetBooleanField(inputWindowObj, - gInputWindowClassInfo.paused); - outInputWindow->layer = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.layer); - outInputWindow->ownerPid = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.ownerPid); - outInputWindow->ownerUid = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.ownerUid); - outInputWindow->inputFeatures = env->GetIntField(inputWindowObj, - gInputWindowClassInfo.inputFeatures); -} - - -// --- JNI --- - -#define FIND_CLASS(var, className) \ - var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); - -#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ - var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ - LOG_FATAL_IF(! var, "Unable to find field " fieldName); - -int register_android_server_InputWindow(JNIEnv* env) { - jclass clazz; - FIND_CLASS(clazz, "com/android/server/wm/InputWindow"); - - GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, clazz, - "inputWindowHandle", "Lcom/android/server/wm/InputWindowHandle;"); - - GET_FIELD_ID(gInputWindowClassInfo.inputChannel, clazz, - "inputChannel", "Landroid/view/InputChannel;"); - - GET_FIELD_ID(gInputWindowClassInfo.name, clazz, - "name", "Ljava/lang/String;"); - - GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, clazz, - "layoutParamsFlags", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, clazz, - "layoutParamsType", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, clazz, - "dispatchingTimeoutNanos", "J"); - - GET_FIELD_ID(gInputWindowClassInfo.frameLeft, clazz, - "frameLeft", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.frameTop, clazz, - "frameTop", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.frameRight, clazz, - "frameRight", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.frameBottom, clazz, - "frameBottom", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.scaleFactor, clazz, - "scaleFactor", "F"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, clazz, - "touchableRegion", "Landroid/graphics/Region;"); - - GET_FIELD_ID(gInputWindowClassInfo.visible, clazz, - "visible", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, clazz, - "canReceiveKeys", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.hasFocus, clazz, - "hasFocus", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, clazz, - "hasWallpaper", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.paused, clazz, - "paused", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.layer, clazz, - "layer", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.ownerPid, clazz, - "ownerPid", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.ownerUid, clazz, - "ownerUid", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.inputFeatures, clazz, - "inputFeatures", "I"); - return 0; -} - -} /* namespace android */ diff --git a/services/jni/com_android_server_InputWindow.h b/services/jni/com_android_server_InputWindow.h deleted file mode 100644 index eaf7bde..0000000 --- a/services/jni/com_android_server_InputWindow.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _ANDROID_SERVER_INPUT_WINDOW_H -#define _ANDROID_SERVER_INPUT_WINDOW_H - -#include <input/InputWindow.h> - -#include "JNIHelp.h" -#include "jni.h" - -namespace android { - -extern void android_server_InputWindow_toNative( - JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow); - -} // namespace android - -#endif // _ANDROID_SERVER_INPUT_WINDOW_H diff --git a/services/jni/com_android_server_InputWindowHandle.cpp b/services/jni/com_android_server_InputWindowHandle.cpp index aaf679c..09be881 100644 --- a/services/jni/com_android_server_InputWindowHandle.cpp +++ b/services/jni/com_android_server_InputWindowHandle.cpp @@ -21,6 +21,9 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/threads.h> +#include <android_view_InputChannel.h> +#include <android/graphics/Region.h> + #include "com_android_server_InputWindowHandle.h" #include "com_android_server_InputApplicationHandle.h" @@ -29,6 +32,26 @@ namespace android { static struct { jfieldID ptr; jfieldID inputApplicationHandle; + jfieldID inputChannel; + jfieldID name; + jfieldID layoutParamsFlags; + jfieldID layoutParamsType; + jfieldID dispatchingTimeoutNanos; + jfieldID frameLeft; + jfieldID frameTop; + jfieldID frameRight; + jfieldID frameBottom; + jfieldID scaleFactor; + jfieldID touchableRegion; + jfieldID visible; + jfieldID canReceiveKeys; + jfieldID hasFocus; + jfieldID hasWallpaper; + jfieldID paused; + jfieldID layer; + jfieldID ownerPid; + jfieldID ownerUid; + jfieldID inputFeatures; } gInputWindowHandleClassInfo; static Mutex gHandleMutex; @@ -51,6 +74,83 @@ jobject NativeInputWindowHandle::getInputWindowHandleObjLocalRef(JNIEnv* env) { return env->NewLocalRef(mObjWeak); } +bool NativeInputWindowHandle::update() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jobject obj = env->NewLocalRef(mObjWeak); + if (!obj) { + return false; + } + + jobject inputChannelObj = env->GetObjectField(obj, + gInputWindowHandleClassInfo.inputChannel); + if (inputChannelObj) { + inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj); + env->DeleteLocalRef(inputChannelObj); + } else { + inputChannel = NULL; + } + + jstring nameObj = jstring(env->GetObjectField(obj, + gInputWindowHandleClassInfo.name)); + if (nameObj) { + const char* nameStr = env->GetStringUTFChars(nameObj, NULL); + name.setTo(nameStr); + env->ReleaseStringUTFChars(nameObj, nameStr); + env->DeleteLocalRef(nameObj); + } else { + name.setTo("<null>"); + } + + layoutParamsFlags = env->GetIntField(obj, + gInputWindowHandleClassInfo.layoutParamsFlags); + layoutParamsType = env->GetIntField(obj, + gInputWindowHandleClassInfo.layoutParamsType); + dispatchingTimeout = env->GetLongField(obj, + gInputWindowHandleClassInfo.dispatchingTimeoutNanos); + frameLeft = env->GetIntField(obj, + gInputWindowHandleClassInfo.frameLeft); + frameTop = env->GetIntField(obj, + gInputWindowHandleClassInfo.frameTop); + frameRight = env->GetIntField(obj, + gInputWindowHandleClassInfo.frameRight); + frameBottom = env->GetIntField(obj, + gInputWindowHandleClassInfo.frameBottom); + scaleFactor = env->GetFloatField(obj, + gInputWindowHandleClassInfo.scaleFactor); + + jobject regionObj = env->GetObjectField(obj, + gInputWindowHandleClassInfo.touchableRegion); + if (regionObj) { + SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj); + touchableRegion.set(*region); + env->DeleteLocalRef(regionObj); + } else { + touchableRegion.setEmpty(); + } + + visible = env->GetBooleanField(obj, + gInputWindowHandleClassInfo.visible); + canReceiveKeys = env->GetBooleanField(obj, + gInputWindowHandleClassInfo.canReceiveKeys); + hasFocus = env->GetBooleanField(obj, + gInputWindowHandleClassInfo.hasFocus); + hasWallpaper = env->GetBooleanField(obj, + gInputWindowHandleClassInfo.hasWallpaper); + paused = env->GetBooleanField(obj, + gInputWindowHandleClassInfo.paused); + layer = env->GetIntField(obj, + gInputWindowHandleClassInfo.layer); + ownerPid = env->GetIntField(obj, + gInputWindowHandleClassInfo.ownerPid); + ownerUid = env->GetIntField(obj, + gInputWindowHandleClassInfo.ownerUid); + inputFeatures = env->GetIntField(obj, + gInputWindowHandleClassInfo.inputFeatures); + + env->DeleteLocalRef(obj); + return true; +} + // --- Global functions --- @@ -127,6 +227,65 @@ int register_android_server_InputWindowHandle(JNIEnv* env) { clazz, "inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;"); + GET_FIELD_ID(gInputWindowHandleClassInfo.inputChannel, clazz, + "inputChannel", "Landroid/view/InputChannel;"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.name, clazz, + "name", "Ljava/lang/String;"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsFlags, clazz, + "layoutParamsFlags", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz, + "layoutParamsType", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutNanos, clazz, + "dispatchingTimeoutNanos", "J"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.frameLeft, clazz, + "frameLeft", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.frameTop, clazz, + "frameTop", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.frameRight, clazz, + "frameRight", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.frameBottom, clazz, + "frameBottom", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.scaleFactor, clazz, + "scaleFactor", "F"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegion, clazz, + "touchableRegion", "Landroid/graphics/Region;"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.visible, clazz, + "visible", "Z"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.canReceiveKeys, clazz, + "canReceiveKeys", "Z"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.hasFocus, clazz, + "hasFocus", "Z"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.hasWallpaper, clazz, + "hasWallpaper", "Z"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz, + "paused", "Z"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.layer, clazz, + "layer", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz, + "ownerPid", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.ownerUid, clazz, + "ownerUid", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.inputFeatures, clazz, + "inputFeatures", "I"); return 0; } diff --git a/services/jni/com_android_server_InputWindowHandle.h b/services/jni/com_android_server_InputWindowHandle.h index 43f2a6b..913c3b1 100644 --- a/services/jni/com_android_server_InputWindowHandle.h +++ b/services/jni/com_android_server_InputWindowHandle.h @@ -32,6 +32,8 @@ public: jobject getInputWindowHandleObjLocalRef(JNIEnv* env); + virtual bool update(); + private: jweak mObjWeak; }; diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index 9dff48b..4178039 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -22,9 +22,7 @@ namespace android { int register_android_server_AlarmManagerService(JNIEnv* env); int register_android_server_BatteryService(JNIEnv* env); -int register_android_server_InputApplication(JNIEnv* env); int register_android_server_InputApplicationHandle(JNIEnv* env); -int register_android_server_InputWindow(JNIEnv* env); int register_android_server_InputWindowHandle(JNIEnv* env); int register_android_server_InputManager(JNIEnv* env); int register_android_server_LightsService(JNIEnv* env); @@ -51,9 +49,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) LOG_ASSERT(env, "Could not retrieve the env!"); register_android_server_PowerManagerService(env); - register_android_server_InputApplication(env); register_android_server_InputApplicationHandle(env); - register_android_server_InputWindow(env); register_android_server_InputWindowHandle(env); register_android_server_InputManager(env); register_android_server_LightsService(env); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java index 260cdc8..fc2f2f8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java @@ -131,6 +131,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public CharSequence getText(int index) { + if (index < 0 || index >= mResourceData.length) { + return null; + } + if (mResourceData[index] != null) { // FIXME: handle styled strings! return mResourceData[index].getValue(); @@ -149,6 +153,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public String getString(int index) { + if (index < 0 || index >= mResourceData.length) { + return null; + } + if (mResourceData[index] != null) { return mResourceData[index].getValue(); } @@ -166,6 +174,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public boolean getBoolean(int index, boolean defValue) { + if (index < 0 || index >= mResourceData.length) { + return defValue; + } + if (mResourceData[index] == null) { return defValue; } @@ -188,6 +200,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public int getInt(int index, int defValue) { + if (index < 0 || index >= mResourceData.length) { + return defValue; + } + if (mResourceData[index] == null) { return defValue; } @@ -252,6 +268,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public float getFloat(int index, float defValue) { + if (index < 0 || index >= mResourceData.length) { + return defValue; + } + if (mResourceData[index] == null) { return defValue; } @@ -287,6 +307,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public int getColor(int index, int defValue) { + if (index < 0 || index >= mResourceData.length) { + return defValue; + } + if (mResourceData[index] == null) { return defValue; } @@ -311,6 +335,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public ColorStateList getColorStateList(int index) { + if (index < 0 || index >= mResourceData.length) { + return null; + } + if (mResourceData[index] == null) { return null; } @@ -395,6 +423,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public float getDimension(int index, float defValue) { + if (index < 0 || index >= mResourceData.length) { + return defValue; + } + if (mResourceData[index] == null) { return defValue; } @@ -568,6 +600,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public float getFraction(int index, int base, int pbase, float defValue) { + if (index < 0 || index >= mResourceData.length) { + return defValue; + } + if (mResourceData[index] == null) { return defValue; } @@ -607,6 +643,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public int getResourceId(int index, int defValue) { + if (index < 0 || index >= mResourceData.length) { + return defValue; + } + // get the Resource for this index ResourceValue resValue = mResourceData[index]; @@ -718,6 +758,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public Drawable getDrawable(int index) { + if (index < 0 || index >= mResourceData.length) { + return null; + } + if (mResourceData[index] == null) { return null; } @@ -744,6 +788,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public CharSequence[] getTextArray(int index) { + if (index < 0 || index >= mResourceData.length) { + return null; + } + if (mResourceData[index] == null) { return null; } @@ -776,6 +824,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public boolean getValue(int index, TypedValue outValue) { + if (index < 0 || index >= mResourceData.length) { + return false; + } + if (mResourceData[index] == null) { return false; } @@ -795,6 +847,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public boolean hasValue(int index) { + if (index < 0 || index >= mResourceData.length) { + return false; + } + return mResourceData[index] != null; } @@ -811,6 +867,10 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public TypedValue peekValue(int index) { + if (index < 0 || index >= mResourceData.length) { + return null; + } + if (getValue(index, mValue)) { return mValue; } diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java index c1affa6..fcdbd2c 100644 --- a/voip/java/android/net/sip/SipAudioCall.java +++ b/voip/java/android/net/sip/SipAudioCall.java @@ -57,6 +57,7 @@ public class SipAudioCall { private static final boolean RELEASE_SOCKET = true; private static final boolean DONT_RELEASE_SOCKET = false; private static final int SESSION_TIMEOUT = 5; // in seconds + private static final int TRANSFER_TIMEOUT = 15; // in seconds /** Listener for events relating to a SIP call, such as when a call is being * recieved ("on ringing") or a call is outgoing ("on calling"). @@ -537,10 +538,14 @@ public class SipAudioCall { Log.v(TAG, "onCallTransferring mSipSession:" + mSipSession + " newSession:" + newSession); mTransferringSession = newSession; - // session changing request try { - String answer = createAnswer(sessionDescription).encode(); - newSession.answerCall(answer, SESSION_TIMEOUT); + if (sessionDescription == null) { + newSession.makeCall(newSession.getPeerProfile(), + createOffer().encode(), TRANSFER_TIMEOUT); + } else { + String answer = createAnswer(sessionDescription).encode(); + newSession.answerCall(answer, SESSION_TIMEOUT); + } } catch (Throwable e) { Log.e(TAG, "onCallTransferring()", e); newSession.endCall(); diff --git a/voip/java/com/android/server/sip/SipHelper.java b/voip/java/com/android/server/sip/SipHelper.java index c031bc1..dc628e0 100644 --- a/voip/java/com/android/server/sip/SipHelper.java +++ b/voip/java/com/android/server/sip/SipHelper.java @@ -19,6 +19,9 @@ package com.android.server.sip; import gov.nist.javax.sip.SipStackExt; import gov.nist.javax.sip.clientauthutils.AccountManager; import gov.nist.javax.sip.clientauthutils.AuthenticationHelper; +import gov.nist.javax.sip.header.extensions.ReferencesHeader; +import gov.nist.javax.sip.header.extensions.ReferredByHeader; +import gov.nist.javax.sip.header.extensions.ReplacesHeader; import android.net.sip.SipProfile; import android.util.Log; @@ -284,14 +287,18 @@ class SipHelper { } public ClientTransaction sendInvite(SipProfile caller, SipProfile callee, - String sessionDescription, String tag) - throws SipException { + String sessionDescription, String tag, ReferredByHeader referredBy, + String replaces) throws SipException { try { Request request = createRequest(Request.INVITE, caller, callee, tag); + if (referredBy != null) request.addHeader(referredBy); + if (replaces != null) { + request.addHeader(mHeaderFactory.createHeader( + ReplacesHeader.NAME, replaces)); + } request.setContent(sessionDescription, mHeaderFactory.createContentTypeHeader( "application", "sdp")); - ClientTransaction clientTransaction = mSipProvider.getNewClientTransaction(request); if (DEBUG) Log.d(TAG, "send INVITE: " + request); @@ -455,6 +462,25 @@ class SipHelper { } } + public void sendReferNotify(Dialog dialog, String content) + throws SipException { + try { + Request request = dialog.createRequest(Request.NOTIFY); + request.addHeader(mHeaderFactory.createSubscriptionStateHeader( + "active;expires=60")); + // set content here + request.setContent(content, + mHeaderFactory.createContentTypeHeader( + "message", "sipfrag")); + request.addHeader(mHeaderFactory.createEventHeader( + ReferencesHeader.REFER)); + if (DEBUG) Log.d(TAG, "send NOTIFY: " + request); + dialog.sendRequest(mSipProvider.getNewClientTransaction(request)); + } catch (ParseException e) { + throw new SipException("sendReferNotify()", e); + } + } + public void sendInviteRequestTerminated(Request inviteRequest, ServerTransaction inviteTransaction) throws SipException { try { diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java index 4e44402..48d9b17 100644 --- a/voip/java/com/android/server/sip/SipSessionGroup.java +++ b/voip/java/com/android/server/sip/SipSessionGroup.java @@ -18,12 +18,15 @@ package com.android.server.sip; import gov.nist.javax.sip.clientauthutils.AccountManager; import gov.nist.javax.sip.clientauthutils.UserCredentials; -import gov.nist.javax.sip.header.SIPHeaderNames; import gov.nist.javax.sip.header.ProxyAuthenticate; +import gov.nist.javax.sip.header.ReferTo; +import gov.nist.javax.sip.header.SIPHeaderNames; +import gov.nist.javax.sip.header.StatusLine; import gov.nist.javax.sip.header.WWWAuthenticate; import gov.nist.javax.sip.header.extensions.ReferredByHeader; import gov.nist.javax.sip.header.extensions.ReplacesHeader; import gov.nist.javax.sip.message.SIPMessage; +import gov.nist.javax.sip.message.SIPResponse; import android.net.sip.ISipSession; import android.net.sip.ISipSessionListener; @@ -71,12 +74,15 @@ import javax.sip.address.SipURI; import javax.sip.header.CSeqHeader; import javax.sip.header.ExpiresHeader; import javax.sip.header.FromHeader; +import javax.sip.header.HeaderAddress; import javax.sip.header.MinExpiresHeader; +import javax.sip.header.ReferToHeader; import javax.sip.header.ViaHeader; import javax.sip.message.Message; import javax.sip.message.Request; import javax.sip.message.Response; + /** * Manages {@link ISipSession}'s for a SIP account. */ @@ -390,25 +396,26 @@ class SipSessionGroup implements SipListener { } } + private SipSessionImpl createNewSession(RequestEvent event, + ISipSessionListener listener, ServerTransaction transaction, + int newState) throws SipException { + SipSessionImpl newSession = new SipSessionImpl(listener); + newSession.mServerTransaction = transaction; + newSession.mState = newState; + newSession.mDialog = newSession.mServerTransaction.getDialog(); + newSession.mInviteReceived = event; + newSession.mPeerProfile = createPeerProfile((HeaderAddress) + event.getRequest().getHeader(FromHeader.NAME)); + newSession.mPeerSessionDescription = + extractContent(event.getRequest()); + return newSession; + } + private class SipSessionCallReceiverImpl extends SipSessionImpl { public SipSessionCallReceiverImpl(ISipSessionListener listener) { super(listener); } - private SipSessionImpl createNewSession(RequestEvent event, - ISipSessionListener listener, ServerTransaction transaction) - throws SipException { - SipSessionImpl newSession = new SipSessionImpl(listener); - newSession.mServerTransaction = transaction; - newSession.mState = SipSession.State.INCOMING_CALL; - newSession.mDialog = newSession.mServerTransaction.getDialog(); - newSession.mInviteReceived = event; - newSession.mPeerProfile = createPeerProfile(event.getRequest()); - newSession.mPeerSessionDescription = - extractContent(event.getRequest()); - return newSession; - } - private int processInviteWithReplaces(RequestEvent event, ReplacesHeader replaces) { String callId = replaces.getCallId(); @@ -452,7 +459,8 @@ class SipSessionGroup implements SipListener { // got INVITE w/ replaces request. newSession = createNewSession(event, replacedSession.mProxy.getListener(), - mSipHelper.getServerTransaction(event)); + mSipHelper.getServerTransaction(event), + SipSession.State.INCOMING_CALL); newSession.mProxy.onCallTransferring(newSession, newSession.mPeerSessionDescription); } else { @@ -461,7 +469,8 @@ class SipSessionGroup implements SipListener { } else { // New Incoming call. newSession = createNewSession(event, mProxy, - mSipHelper.sendRinging(event, generateTag())); + mSipHelper.sendRinging(event, generateTag()), + SipSession.State.INCOMING_CALL); mProxy.onRinging(newSession, newSession.mPeerProfile, newSession.mPeerSessionDescription); } @@ -507,6 +516,11 @@ class SipSessionGroup implements SipListener { private SipSessionImpl mKeepAliveSession; + // the following three members are used for handling refer request. + SipSessionImpl mReferSession; + ReferredByHeader mReferredBy; + String mReplaces; + // lightweight timer class SessionTimer { private boolean mRunning = true; @@ -556,6 +570,9 @@ class SipSessionGroup implements SipListener { mInviteReceived = null; mPeerSessionDescription = null; mAuthenticationRetryCount = 0; + mReferSession = null; + mReferredBy = null; + mReplaces = null; if (mDialog != null) mDialog.delete(); mDialog = null; @@ -969,15 +986,26 @@ class SipSessionGroup implements SipListener { return (proxyAuth == null) ? null : proxyAuth.getNonce(); } + private String getResponseString(int statusCode) { + StatusLine statusLine = new StatusLine(); + statusLine.setStatusCode(statusCode); + statusLine.setReasonPhrase(SIPResponse.getReasonPhrase(statusCode)); + return statusLine.encode(); + } + private boolean readyForCall(EventObject evt) throws SipException { // expect MakeCallCommand, RegisterCommand, DEREGISTER if (evt instanceof MakeCallCommand) { mState = SipSession.State.OUTGOING_CALL; MakeCallCommand cmd = (MakeCallCommand) evt; mPeerProfile = cmd.getPeerProfile(); - mClientTransaction = mSipHelper.sendInvite(mLocalProfile, - mPeerProfile, cmd.getSessionDescription(), - generateTag()); + if (mReferSession != null) { + mSipHelper.sendReferNotify(mReferSession.mDialog, + getResponseString(Response.TRYING)); + } + mClientTransaction = mSipHelper.sendInvite( + mLocalProfile, mPeerProfile, cmd.getSessionDescription(), + generateTag(), mReferredBy, mReplaces); mDialog = mClientTransaction.getDialog(); addSipSession(this); startSessionTimer(cmd.getTimeout()); @@ -1072,6 +1100,12 @@ class SipSessionGroup implements SipListener { } return true; case Response.OK: + if (mReferSession != null) { + mSipHelper.sendReferNotify(mReferSession.mDialog, + getResponseString(Response.OK)); + // since we don't need to remember the session anymore. + mReferSession = null; + } mSipHelper.sendInviteAck(event, mDialog); mPeerSessionDescription = extractContent(response); establishCall(true); @@ -1087,6 +1121,10 @@ class SipSessionGroup implements SipListener { // rfc3261#section-14.1; re-schedule invite return true; default: + if (mReferSession != null) { + mSipHelper.sendReferNotify(mReferSession.mDialog, + getResponseString(Response.SERVICE_UNAVAILABLE)); + } if (statusCode >= 400) { // error: an ack is sent automatically by the stack onError(response); @@ -1155,6 +1193,38 @@ class SipSessionGroup implements SipListener { return false; } + private boolean processReferRequest(RequestEvent event) + throws SipException { + try { + ReferToHeader referto = (ReferToHeader) event.getRequest() + .getHeader(ReferTo.NAME); + Address address = referto.getAddress(); + SipURI uri = (SipURI) address.getURI(); + String replacesHeader = uri.getHeader(ReplacesHeader.NAME); + String username = uri.getUser(); + if (username == null) { + mSipHelper.sendResponse(event, Response.BAD_REQUEST); + return false; + } + // send notify accepted + mSipHelper.sendResponse(event, Response.ACCEPTED); + SipSessionImpl newSession = createNewSession(event, + this.mProxy.getListener(), + mSipHelper.getServerTransaction(event), + SipSession.State.READY_TO_CALL); + newSession.mReferSession = this; + newSession.mReferredBy = (ReferredByHeader) event.getRequest() + .getHeader(ReferredByHeader.NAME); + newSession.mReplaces = replacesHeader; + newSession.mPeerProfile = createPeerProfile(referto); + newSession.mProxy.onCallTransferring(newSession, + null); + return true; + } catch (IllegalArgumentException e) { + throw new SipException("createPeerProfile()", e); + } + } + private boolean inCall(EventObject evt) throws SipException { // expect END_CALL cmd, BYE request, hold call (MakeCallCommand) // OK retransmission is handled in SipStack @@ -1175,6 +1245,8 @@ class SipSessionGroup implements SipListener { mSipHelper.sendResponse((RequestEvent) evt, Response.OK); endCallNormally(); return true; + } else if (isRequestEvent(Request.REFER, evt)) { + return processReferRequest((RequestEvent) evt); } else if (evt instanceof MakeCallCommand) { // to change call mState = SipSession.State.OUTGOING_CALL; @@ -1182,6 +1254,8 @@ class SipSessionGroup implements SipListener { ((MakeCallCommand) evt).getSessionDescription()); startSessionTimer(((MakeCallCommand) evt).getTimeout()); return true; + } else if (evt instanceof ResponseEvent) { + if (expectResponse(Request.NOTIFY, evt)) return true; } return false; } @@ -1558,12 +1632,10 @@ class SipSessionGroup implements SipListener { return false; } - private static SipProfile createPeerProfile(Request request) + private static SipProfile createPeerProfile(HeaderAddress header) throws SipException { try { - FromHeader fromHeader = - (FromHeader) request.getHeader(FromHeader.NAME); - Address address = fromHeader.getAddress(); + Address address = header.getAddress(); SipURI uri = (SipURI) address.getURI(); String username = uri.getUser(); if (username == null) username = ANONYMOUS; |
