Merge "Don't handle click if the resolver is already finishing." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index e96eec2..db8f224 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20,6 +20,7 @@
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+ field public static final java.lang.String BIND_CALL_SERVICE = "android.permission.BIND_CALL_SERVICE";
field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
@@ -638,13 +639,13 @@
field public static final int keyPreviewHeight = 16843321; // 0x1010239
field public static final int keyPreviewLayout = 16843319; // 0x1010237
field public static final int keyPreviewOffset = 16843320; // 0x1010238
+ field public static final int keySet = 16843739; // 0x10103db
field public static final int keyTextColor = 16843318; // 0x1010236
field public static final int keyTextSize = 16843316; // 0x1010234
field public static final int keyWidth = 16843325; // 0x101023d
field public static final int keyboardLayout = 16843691; // 0x10103ab
field public static final int keyboardMode = 16843341; // 0x101024d
field public static final int keycode = 16842949; // 0x10100c5
- field public static final int keyset = 16843739; // 0x10103db
field public static final int killAfterRestore = 16843420; // 0x101029c
field public static final int label = 16842753; // 0x1010001
field public static final int labelFor = 16843718; // 0x10103c6
@@ -6521,6 +6522,7 @@
field public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 32; // 0x20
field public static final int FLAG_PERSIST_GRANT_URI_PERMISSION = 64; // 0x40
field public static final int FLAG_RECEIVER_FOREGROUND = 268435456; // 0x10000000
+ field public static final int FLAG_RECEIVER_NO_ABORT = 134217728; // 0x8000000
field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
@@ -12430,7 +12432,7 @@
method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
method public final void release();
method public final void releaseOutputBuffer(int, boolean);
- method public final void setParameters(java.util.Map<java.lang.String, java.lang.Object>);
+ method public final void setParameters(android.os.Bundle);
method public final void setVideoScalingMode(int);
method public final void signalEndOfInputStream();
method public final void start();
@@ -12446,7 +12448,7 @@
field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
field public static final java.lang.String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
field public static final java.lang.String PARAMETER_KEY_SUSPEND = "drop-input-frames";
- field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "videoBitrate";
+ field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
}
@@ -12757,6 +12759,9 @@
field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
field public static final java.lang.String KEY_HEIGHT = "height";
field public static final java.lang.String KEY_IS_ADTS = "is-adts";
+ field public static final java.lang.String KEY_IS_AUTOSELECT = "is-autoselect";
+ field public static final java.lang.String KEY_IS_DEFAULT = "is-default";
+ field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
field public static final java.lang.String KEY_LANGUAGE = "language";
field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
@@ -12769,6 +12774,25 @@
field public static final java.lang.String KEY_WIDTH = "width";
}
+ public abstract class MediaMetadataEditor {
+ method public synchronized void addEditableKey(int);
+ method public abstract void apply();
+ method public synchronized void clear();
+ method public synchronized android.graphics.Bitmap getBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+ method public synchronized int[] getEditableKeys();
+ method public synchronized long getLong(int, long) throws java.lang.IllegalArgumentException;
+ method public synchronized java.lang.Object getObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+ method public synchronized java.lang.String getString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+ method public synchronized android.media.MediaMetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+ method public synchronized android.media.MediaMetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
+ method public synchronized android.media.MediaMetadataEditor putObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+ method public synchronized android.media.MediaMetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+ method public synchronized void removeEditableKeys();
+ field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
+ field public static final int RATING_KEY_BY_OTHERS = 101; // 0x65
+ field public static final int RATING_KEY_BY_USER = 268435457; // 0x10000001
+ }
+
public class MediaMetadataRetriever {
ctor public MediaMetadataRetriever();
method public java.lang.String extractMetadata(int);
@@ -13185,6 +13209,29 @@
ctor public NotProvisionedException(java.lang.String);
}
+ public final class Rating implements android.os.Parcelable {
+ method public int describeContents();
+ method public float getPercentRating();
+ method public int getRatingStyle();
+ method public float getStarRating();
+ method public boolean hasHeart();
+ method public boolean isRated();
+ method public boolean isThumbUp();
+ method public static android.media.Rating newHeartRating(boolean);
+ method public static android.media.Rating newPercentageRating(float);
+ method public static android.media.Rating newStarRating(int, float);
+ method public static android.media.Rating newThumbRating(boolean);
+ method public static android.media.Rating newUnratedRating(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int RATING_3_STARS = 3; // 0x3
+ field public static final int RATING_4_STARS = 4; // 0x4
+ field public static final int RATING_5_STARS = 5; // 0x5
+ field public static final int RATING_HEART = 1; // 0x1
+ field public static final int RATING_PERCENTAGE = 6; // 0x6
+ field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+ }
+
public class RemoteControlClient {
ctor public RemoteControlClient(android.app.PendingIntent);
ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
@@ -13216,21 +13263,9 @@
field public static final int PLAYSTATE_STOPPED = 1; // 0x1
}
- public class RemoteControlClient.MetadataEditor {
- method public synchronized void addEditableKey(int);
+ public class RemoteControlClient.MetadataEditor extends android.media.MediaMetadataEditor {
method public synchronized void apply();
- method public synchronized void clear();
- method public synchronized void clearEditableKeys();
- method public synchronized android.media.RemoteControlClient.MetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
- method public synchronized android.media.RemoteControlClient.MetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
- method public synchronized android.media.RemoteControlClient.MetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
- field public static final int LONG_KEY_RATING_BY_OTHERS = 102; // 0x66
- field public static final int LONG_KEY_RATING_BY_USER = 268435457; // 0x10000001
- field public static final int LONG_KEY_RATING_TYPE = 101; // 0x65
- field public static final long RATING_HEART = -1L; // 0xffffffffffffffffL
- field public static final long RATING_NOT_RATED = -101L; // 0xffffffffffffff9bL
- field public static final long RATING_THUMB_UP_DOWN = -2L; // 0xfffffffffffffffeL
}
public static abstract interface RemoteControlClient.OnGetPlaybackPositionListener {
@@ -13238,9 +13273,7 @@
}
public static abstract interface RemoteControlClient.OnMetadataUpdateListener {
- method public abstract void onMetadataUpdateBitmap(int, android.graphics.Bitmap);
- method public abstract void onMetadataUpdateLong(int, long);
- method public abstract void onMetadataUpdateString(int, java.lang.String);
+ method public abstract void onMetadataUpdate(int, java.lang.Object);
}
public static abstract interface RemoteControlClient.OnPlaybackPositionUpdateListener {
@@ -19115,12 +19148,54 @@
field public static final android.print.PrintAttributes.MediaSize ISO_C7;
field public static final android.print.PrintAttributes.MediaSize ISO_C8;
field public static final android.print.PrintAttributes.MediaSize ISO_C9;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B0;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B1;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B10;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B2;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B3;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B4;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B5;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B6;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B7;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B8;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B9;
+ field public static final android.print.PrintAttributes.MediaSize JIS_EXEC;
+ field public static final android.print.PrintAttributes.MediaSize JPN_CHOU2;
+ field public static final android.print.PrintAttributes.MediaSize JPN_CHOU3;
+ field public static final android.print.PrintAttributes.MediaSize JPN_CHOU4;
+ field public static final android.print.PrintAttributes.MediaSize JPN_HAGAKI;
+ field public static final android.print.PrintAttributes.MediaSize JPN_KAHU;
+ field public static final android.print.PrintAttributes.MediaSize JPN_KAKU2;
+ field public static final android.print.PrintAttributes.MediaSize JPN_OUFUKU;
+ field public static final android.print.PrintAttributes.MediaSize JPN_YOU4;
+ field public static final android.print.PrintAttributes.MediaSize NA_FOOLSCAP;
field public static final android.print.PrintAttributes.MediaSize NA_GOVT_LETTER;
+ field public static final android.print.PrintAttributes.MediaSize NA_INDEX_3X5;
+ field public static final android.print.PrintAttributes.MediaSize NA_INDEX_4X6;
+ field public static final android.print.PrintAttributes.MediaSize NA_INDEX_5X8;
field public static final android.print.PrintAttributes.MediaSize NA_JUNIOR_LEGAL;
field public static final android.print.PrintAttributes.MediaSize NA_LEDGER;
field public static final android.print.PrintAttributes.MediaSize NA_LEGAL;
field public static final android.print.PrintAttributes.MediaSize NA_LETTER;
+ field public static final android.print.PrintAttributes.MediaSize NA_MONARCH;
+ field public static final android.print.PrintAttributes.MediaSize NA_QUARTO;
field public static final android.print.PrintAttributes.MediaSize NA_TBLOID;
+ field public static final android.print.PrintAttributes.MediaSize OM_DAI_PA_KAI;
+ field public static final android.print.PrintAttributes.MediaSize OM_JUURO_KU_KAI;
+ field public static final android.print.PrintAttributes.MediaSize OM_PA_KAI;
+ field public static final android.print.PrintAttributes.MediaSize PRC_1;
+ field public static final android.print.PrintAttributes.MediaSize PRC_10;
+ field public static final android.print.PrintAttributes.MediaSize PRC_16k;
+ field public static final android.print.PrintAttributes.MediaSize PRC_2;
+ field public static final android.print.PrintAttributes.MediaSize PRC_3;
+ field public static final android.print.PrintAttributes.MediaSize PRC_4;
+ field public static final android.print.PrintAttributes.MediaSize PRC_5;
+ field public static final android.print.PrintAttributes.MediaSize PRC_6;
+ field public static final android.print.PrintAttributes.MediaSize PRC_7;
+ field public static final android.print.PrintAttributes.MediaSize PRC_8;
+ field public static final android.print.PrintAttributes.MediaSize PRC_9;
+ field public static final android.print.PrintAttributes.MediaSize ROC_16K;
+ field public static final android.print.PrintAttributes.MediaSize ROC_8K;
}
public static final class PrintAttributes.Resolution {
@@ -24944,9 +25019,7 @@
method public static void clearMetaKeyState(android.text.Editable, int);
method public long clearMetaKeyState(long, int);
method public static final int getMetaState(java.lang.CharSequence);
- method public static final int getMetaState(java.lang.CharSequence, android.view.KeyEvent);
method public static final int getMetaState(java.lang.CharSequence, int);
- method public static final int getMetaState(java.lang.CharSequence, int, android.view.KeyEvent);
method public static final int getMetaState(long);
method public static final int getMetaState(long, int);
method public static long handleKeyDown(long, int, android.view.KeyEvent);
@@ -27265,6 +27338,7 @@
method public float getScaleFactor();
method public long getTimeDelta();
method public boolean isInProgress();
+ method public boolean isQuickScaleEnabled();
method public boolean onTouchEvent(android.view.MotionEvent);
method public void setQuickScaleEnabled(boolean);
}
@@ -29935,7 +30009,7 @@
method public deprecated void onConsoleMessage(java.lang.String, int, java.lang.String);
method public boolean onConsoleMessage(android.webkit.ConsoleMessage);
method public boolean onCreateWindow(android.webkit.WebView, boolean, boolean, android.os.Message);
- method public void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
+ method public deprecated void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
method public void onGeolocationPermissionsHidePrompt();
method public void onGeolocationPermissionsShowPrompt(java.lang.String, android.webkit.GeolocationPermissions.Callback);
method public void onHideCustomView();
@@ -29945,7 +30019,7 @@
method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
method public deprecated boolean onJsTimeout();
method public void onProgressChanged(android.webkit.WebView, int);
- method public void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
+ method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
method public void onReceivedTitle(android.webkit.WebView, java.lang.String);
method public void onReceivedTouchIconUrl(android.webkit.WebView, java.lang.String, boolean);
@@ -30001,12 +30075,12 @@
method public int getCacheMode();
method public synchronized java.lang.String getCursiveFontFamily();
method public synchronized boolean getDatabaseEnabled();
- method public synchronized java.lang.String getDatabasePath();
+ method public deprecated synchronized java.lang.String getDatabasePath();
method public synchronized int getDefaultFixedFontSize();
method public synchronized int getDefaultFontSize();
method public synchronized java.lang.String getDefaultTextEncodingName();
method public static java.lang.String getDefaultUserAgent(android.content.Context);
- method public android.webkit.WebSettings.ZoomDensity getDefaultZoom();
+ method public deprecated android.webkit.WebSettings.ZoomDensity getDefaultZoom();
method public boolean getDisplayZoomControls();
method public synchronized boolean getDomStorageEnabled();
method public synchronized java.lang.String getFantasyFontFamily();
@@ -30043,11 +30117,11 @@
method public void setCacheMode(int);
method public synchronized void setCursiveFontFamily(java.lang.String);
method public synchronized void setDatabaseEnabled(boolean);
- method public synchronized void setDatabasePath(java.lang.String);
+ method public deprecated synchronized void setDatabasePath(java.lang.String);
method public synchronized void setDefaultFixedFontSize(int);
method public synchronized void setDefaultFontSize(int);
method public synchronized void setDefaultTextEncodingName(java.lang.String);
- method public void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
+ method public deprecated void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
method public void setDisplayZoomControls(boolean);
method public synchronized void setDomStorageEnabled(boolean);
method public deprecated void setEnableSmoothTransition(boolean);
@@ -30090,9 +30164,10 @@
public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
method public static android.webkit.WebSettings.LayoutAlgorithm valueOf(java.lang.String);
method public static final android.webkit.WebSettings.LayoutAlgorithm[] values();
- enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
+ enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NORMAL;
enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
+ enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm TEXT_AUTOSIZING;
}
public static final class WebSettings.PluginState extends java.lang.Enum {
@@ -30145,7 +30220,7 @@
method public long getUsage();
}
- public static abstract interface WebStorage.QuotaUpdater {
+ public static abstract deprecated interface WebStorage.QuotaUpdater {
method public abstract void updateQuota(long);
}
@@ -30173,7 +30248,7 @@
method public boolean canGoForward();
method public deprecated boolean canZoomIn();
method public deprecated boolean canZoomOut();
- method public android.graphics.Picture capturePicture();
+ method public deprecated android.graphics.Picture capturePicture();
method public void clearCache(boolean);
method public void clearFormData();
method public void clearHistory();
@@ -30190,7 +30265,7 @@
method public void findAllAsync(java.lang.String);
method public void findNext(boolean);
method public void flingScroll(int, int);
- method public void freeMemory();
+ method public deprecated void freeMemory();
method public android.net.http.SslCertificate getCertificate();
method public int getContentHeight();
method public android.graphics.Bitmap getFavicon();
@@ -31535,6 +31610,8 @@
ctor public NumberPicker(android.content.Context);
ctor public NumberPicker(android.content.Context, android.util.AttributeSet);
ctor public NumberPicker(android.content.Context, android.util.AttributeSet, int);
+ method public int computeVerticalScrollOffset();
+ method public int computeVerticalScrollRange();
method public java.lang.String[] getDisplayedValues();
method public int getMaxValue();
method public int getMinValue();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 3e4795c..bf2a1e4 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -65,7 +65,7 @@
// when adding one of these:
// - increment _NUM_OP
- // - add rows to sOpToSwitch, sOpNames, sOpPerms
+ // - add rows to sOpToSwitch, sOpNames, sOpPerms, sOpDefaultMode
// - add descriptive strings to Settings/res/values/arrays.xml
// - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
@@ -315,6 +315,55 @@
};
/**
+ * This specifies the default mode for each operation.
+ */
+ private static int[] sOpDefaultMode = new int[] {
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_IGNORED, // OP_WRITE_SMS
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ };
+
+ /**
* Retrieve the op switch that controls the given operation.
* @hide
*/
@@ -339,6 +388,14 @@
}
/**
+ * Retrieve the default mode for the operation.
+ * @hide
+ */
+ public static int opToDefaultMode(int op) {
+ return sOpDefaultMode[op];
+ }
+
+ /**
* Class holding all of the operation information associated with an app.
* @hide
*/
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 0a1d3f9a..9a258dc 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1573,8 +1573,10 @@
*/
if (mContext == null) {
mContext = context;
- mTransport.mAppOpsManager = (AppOpsManager) mContext.getSystemService(
- Context.APP_OPS_SERVICE);
+ if (context != null) {
+ mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
+ Context.APP_OPS_SERVICE);
+ }
mMyUid = Process.myUid();
if (info != null) {
setReadPermission(info.readPermission);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f250029..5618cab 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2316,8 +2316,7 @@
}
@Override
- public void close() throws IOException {
- super.close();
+ public void releaseResources() {
if (!mProviderReleased) {
ContentResolver.this.releaseProvider(mContentProvider);
mProviderReleased = true;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7925123..dcc6328 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3588,6 +3588,12 @@
*/
public static final int FLAG_RECEIVER_FOREGROUND = 0x10000000;
/**
+ * If this is an ordered broadcast, don't allow receivers to abort the broadcast.
+ * They can still propagate results through to later receivers, but they can not prevent
+ * later receivers from seeing the broadcast.
+ */
+ public static final int FLAG_RECEIVER_NO_ABORT = 0x08000000;
+ /**
* If set, when sending a broadcast <i>before boot has completed</i> only
* registered receivers will be called -- no BroadcastReceiver components
* will be launched. Sticky intent state will be recorded properly even
@@ -3600,14 +3606,14 @@
*
* @hide
*/
- public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x08000000;
+ public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x04000000;
/**
* Set when this broadcast is for a boot upgrade, a special mode that
* allows the broadcast to be sent before the system is ready and launches
* the app process with no providers running in it.
* @hide
*/
- public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x04000000;
+ public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x02000000;
/**
* @hide Flags that can't be changed with PendingIntent.
diff --git a/core/java/android/hardware/camera2/CameraProperties.java b/core/java/android/hardware/camera2/CameraProperties.java
index 58a1ee3..a2faf09f 100644
--- a/core/java/android/hardware/camera2/CameraProperties.java
+++ b/core/java/android/hardware/camera2/CameraProperties.java
@@ -415,6 +415,14 @@
* platform opaque YUV/RGB streams to the GPU or video
* encoders. Listed as width, height
* </p>
+ * <p>
+ * The actual supported resolution list may be limited by
+ * consumer end points for different use cases. For example, for
+ * recording use case, the largest supported resolution may be
+ * limited by max supported size from encoder, for preview use
+ * case, the largest supported resolution may be limited by max
+ * resolution SurfaceTexture/SurfaceView can support.
+ * </p>
*/
public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 40a3612..d0feaa3 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -255,6 +255,10 @@
return mRequiresDeviceUnlock;
}
+ public String getDescription() {
+ return mDescription;
+ }
+
public CharSequence loadLabel(PackageManager pm) {
return mService.loadLabel(pm);
}
@@ -287,6 +291,11 @@
Log.e(TAG, "AID " + aid + " is not correctly formatted.");
return false;
}
+ // Minimum AID length is 5 bytes, 10 hex chars
+ if (aidLength < 10) {
+ Log.e(TAG, "AID " + aid + " is shorter than 5 bytes.");
+ return false;
+ }
return true;
}
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 579971d..5a49b98 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -564,7 +564,11 @@
@Override
public void close() throws IOException {
if (mWrapped != null) {
- mWrapped.close();
+ try {
+ mWrapped.close();
+ } finally {
+ releaseResources();
+ }
} else {
closeWithStatus(Status.OK, null);
}
@@ -579,7 +583,11 @@
*/
public void closeWithError(String msg) throws IOException {
if (mWrapped != null) {
- mWrapped.closeWithError(msg);
+ try {
+ mWrapped.closeWithError(msg);
+ } finally {
+ releaseResources();
+ }
} else {
if (msg == null) {
throw new IllegalArgumentException("Message must not be null");
@@ -588,17 +596,22 @@
}
}
- private void closeWithStatus(int status, String msg) throws IOException {
- if (mWrapped != null) {
- mWrapped.closeWithStatus(status, msg);
- } else {
- if (mClosed) return;
- mClosed = true;
- mGuard.close();
- // Status MUST be sent before closing actual descriptor
- writeCommStatusAndClose(status, msg);
- IoUtils.closeQuietly(mFd);
- }
+ private void closeWithStatus(int status, String msg) {
+ if (mClosed) return;
+ mClosed = true;
+ mGuard.close();
+ // Status MUST be sent before closing actual descriptor
+ writeCommStatusAndClose(status, msg);
+ IoUtils.closeQuietly(mFd);
+ releaseResources();
+ }
+
+ /**
+ * Called when the fd is being closed, for subclasses to release any other resources
+ * associated with it, such as acquired providers.
+ * @hide
+ */
+ public void releaseResources() {
}
private byte[] getOrCreateStatusBuffer() {
@@ -793,6 +806,9 @@
@Override
protected void finalize() throws Throwable {
+ if (mWrapped != null) {
+ releaseResources();
+ }
if (mGuard != null) {
mGuard.warnIfOpen();
}
@@ -822,7 +838,11 @@
@Override
public void writeToParcel(Parcel out, int flags) {
if (mWrapped != null) {
- mWrapped.writeToParcel(out, flags);
+ try {
+ mWrapped.writeToParcel(out, flags);
+ } finally {
+ releaseResources();
+ }
} else {
out.writeFileDescriptor(mFd);
if (mCommFd != null) {
@@ -832,11 +852,8 @@
out.writeInt(0);
}
if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
- try {
- // Not a real close, so emit no status
- closeWithStatus(Status.SILENCE, null);
- } catch (IOException e) {
- }
+ // Not a real close, so emit no status
+ closeWithStatus(Status.SILENCE, null);
}
}
}
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index d889353..efe6b15 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -373,27 +373,208 @@
// North America
- /** North America Letter media size: 8.5" x 11" */
+ /** North America Letter media size: 8.5" x 11" (279mm x 216mm) */
public static final MediaSize NA_LETTER =
new MediaSize("NA_LETTER", "android", R.string.mediaSize_na_letter, 8500, 11000);
- /** North America Government-Letter media size: 8.0" x 10.5" */
+ /** North America Government-Letter media size: 8.0" x 10.5" (203mm x 267mm) */
public static final MediaSize NA_GOVT_LETTER =
new MediaSize("NA_GOVT_LETTER", "android",
R.string.mediaSize_na_gvrnmt_letter, 8000, 10500);
- /** North America Legal media size: 8.5" x 14" */
+ /** North America Legal media size: 8.5" x 14" (216mm x 356mm) */
public static final MediaSize NA_LEGAL =
new MediaSize("NA_LEGAL", "android", R.string.mediaSize_na_legal, 8500, 14000);
- /** North America Junior Legal media size: 8.0" x 5.0" */
+ /** North America Junior Legal media size: 8.0" x 5.0" (203mm × 127mm) */
public static final MediaSize NA_JUNIOR_LEGAL =
new MediaSize("NA_JUNIOR_LEGAL", "android",
R.string.mediaSize_na_junior_legal, 8000, 5000);
- /** North America Ledger media size: 17" x 11" */
+ /** North America Ledger media size: 17" x 11" (432mm × 279mm) */
public static final MediaSize NA_LEDGER =
new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000);
- /** North America Tabloid media size: 11" x 17" */
+ /** North America Tabloid media size: 11" x 17" (279mm × 432mm) */
public static final MediaSize NA_TBLOID =
new MediaSize("NA_TABLOID", "android",
R.string.mediaSize_na_tabloid, 11000, 17000);
+ /** North America Index Card 3x5 media size: 3" x 5" (76mm x 127mm) */
+ public static final MediaSize NA_INDEX_3X5 =
+ new MediaSize("NA_INDEX_3X5", "android",
+ R.string.mediaSize_na_index_3x5, 3000, 5000);
+ /** North America Index Card 4x6 media size: 4" x 6" (102mm x 152mm) */
+ public static final MediaSize NA_INDEX_4X6 =
+ new MediaSize("NA_INDEX_4X6", "android",
+ R.string.mediaSize_na_index_4x6, 4000, 6000);
+ /** North America Index Card 5x8 media size: 5" x 8" (127mm x 203mm) */
+ public static final MediaSize NA_INDEX_5X8 =
+ new MediaSize("NA_INDEX_5X8", "android",
+ R.string.mediaSize_na_index_5x8, 5000, 8000);
+ /** North America Monarch media size: 7.25" x 10.5" (184mm x 267mm) */
+ public static final MediaSize NA_MONARCH =
+ new MediaSize("NA_MONARCH", "android",
+ R.string.mediaSize_na_monarch, 7250, 10500);
+ /** North America Quarto media size: 8" x 10" (203mm x 254mm) */
+ public static final MediaSize NA_QUARTO =
+ new MediaSize("NA_QUARTO", "android",
+ R.string.mediaSize_na_quarto, 8000, 10000);
+ /** North America Foolscap media size: 8" x 13" (203mm x 330mm) */
+ public static final MediaSize NA_FOOLSCAP =
+ new MediaSize("NA_FOOLSCAP", "android",
+ R.string.mediaSize_na_foolscap, 8000, 13000);
+
+ // Chinese
+
+ /** Chinese ROC 8K media size: 270mm x 390mm (10.629" x 15.3543") */
+ public static final MediaSize ROC_8K =
+ new MediaSize("ROC_8K", "android",
+ R.string.mediaSize_chinese_roc_8k, 10629, 15354);
+ /** Chinese ROC 16K media size: 195mm x 270mm (7.677" x 10.629") */
+ public static final MediaSize ROC_16K =
+ new MediaSize("ROC_16K", "android",
+ R.string.mediaSize_chinese_roc_16k, 7677, 10629);
+
+ /** Chinese PRC 1 media size: 102mm x 165mm (4.015" x 6.496") */
+ public static final MediaSize PRC_1 =
+ new MediaSize("PRC_1", "android",
+ R.string.mediaSize_chinese_prc_1, 4015, 6496);
+ /** Chinese PRC 2 media size: 102mm x 176mm (4.015" x 6.929") */
+ public static final MediaSize PRC_2 =
+ new MediaSize("PRC_2", "android",
+ R.string.mediaSize_chinese_prc_2, 4015, 6929);
+ /** Chinese PRC 3 media size: 125mm x 176mm (4.921" x 6.929") */
+ public static final MediaSize PRC_3 =
+ new MediaSize("PRC_3", "android",
+ R.string.mediaSize_chinese_prc_3, 4921, 6929);
+ /** Chinese PRC 4 media size: 110mm x 208mm (4.330" x 8.189") */
+ public static final MediaSize PRC_4 =
+ new MediaSize("PRC_4", "android",
+ R.string.mediaSize_chinese_prc_4, 4330, 8189);
+ /** Chinese PRC 5 media size: 110mm x 220mm (4.330" x 8.661") */
+ public static final MediaSize PRC_5 =
+ new MediaSize("PRC_5", "android",
+ R.string.mediaSize_chinese_prc_5, 4330, 8661);
+ /** Chinese PRC 6 media size: 120mm x 320mm (4.724" x 12.599") */
+ public static final MediaSize PRC_6 =
+ new MediaSize("PRC_6", "android",
+ R.string.mediaSize_chinese_prc_6, 4724, 12599);
+ /** Chinese PRC 7 media size: 160mm x 230mm (6.299" x 9.055") */
+ public static final MediaSize PRC_7 =
+ new MediaSize("PRC_7", "android",
+ R.string.mediaSize_chinese_prc_7, 6299, 9055);
+ /** Chinese PRC 8 media size: 120mm x 309mm (4.724" x 12.165") */
+ public static final MediaSize PRC_8 =
+ new MediaSize("PRC_8", "android",
+ R.string.mediaSize_chinese_prc_8, 4724, 12165);
+ /** Chinese PRC 9 media size: 229mm x 324mm (9.016" x 12.756") */
+ public static final MediaSize PRC_9 =
+ new MediaSize("PRC_9", "android",
+ R.string.mediaSize_chinese_prc_9, 9016, 12756);
+ /** Chinese PRC 10 media size: 324mm x 458mm (12.756" x 18.032") */
+ public static final MediaSize PRC_10 =
+ new MediaSize("PRC_10", "android",
+ R.string.mediaSize_chinese_prc_10, 12756, 18032);
+
+ /** Chinese PRC 16k media size: 146mm x 215mm (5.749" x 8.465") */
+ public static final MediaSize PRC_16k =
+ new MediaSize("PRC_16k", "android",
+ R.string.mediaSize_chinese_prc_16k, 5749, 8465);
+ /** Chinese Pa Kai media size: 267mm x 389mm (10.512" x 15.315") */
+ public static final MediaSize OM_PA_KAI =
+ new MediaSize("OM_PA_KAI", "android",
+ R.string.mediaSize_chinese_om_pa_kai, 10512, 15315);
+ /** Chinese Dai Pa Kai media size: 275mm x 395mm (10.827" x 15.551") */
+ public static final MediaSize OM_DAI_PA_KAI =
+ new MediaSize("OM_DAI_PA_KAI", "android",
+ R.string.mediaSize_chinese_om_dai_pa_kai, 10827, 15551);
+ /** Chinese Jurro Ku Kai media size: 198mm x 275mm (7.796" x 10.827") */
+ public static final MediaSize OM_JUURO_KU_KAI =
+ new MediaSize("OM_JUURO_KU_KAI", "android",
+ R.string.mediaSize_chinese_om_jurro_ku_kai, 7796, 10827);
+
+ // Japanese
+
+ /** Japanese JIS B10 media size: 32mm x 45mm (1.259" x 1.772") */
+ public static final MediaSize JIS_B10 =
+ new MediaSize("JIS_B10", "android",
+ R.string.mediaSize_japanese_jis_b10, 1259, 1772);
+ /** Japanese JIS B9 media size: 45mm x 64mm (1.772" x 2.52") */
+ public static final MediaSize JIS_B9 =
+ new MediaSize("JIS_B9", "android",
+ R.string.mediaSize_japanese_jis_b9, 1772, 2520);
+ /** Japanese JIS B8 media size: 64mm x 91mm (2.52" x 3.583") */
+ public static final MediaSize JIS_B8 =
+ new MediaSize("JIS_B8", "android",
+ R.string.mediaSize_japanese_jis_b8, 2520, 3583);
+ /** Japanese JIS B7 media size: 91mm x 128mm (3.583" x 5.049") */
+ public static final MediaSize JIS_B7 =
+ new MediaSize("JIS_B7", "android",
+ R.string.mediaSize_japanese_jis_b7, 3583, 5049);
+ /** Japanese JIS B6 media size: 128mm x 182mm (5.049" x 7.165") */
+ public static final MediaSize JIS_B6 =
+ new MediaSize("JIS_B6", "android",
+ R.string.mediaSize_japanese_jis_b6, 5049, 7165);
+ /** Japanese JIS B5 media size: 182mm x 257mm (7.165" x 10.118") */
+ public static final MediaSize JIS_B5 =
+ new MediaSize("JIS_B5", "android",
+ R.string.mediaSize_japanese_jis_b5, 7165, 10118);
+ /** Japanese JIS B4 media size: 257mm x 364mm (10.118" x 14.331") */
+ public static final MediaSize JIS_B4 =
+ new MediaSize("JIS_B4", "android",
+ R.string.mediaSize_japanese_jis_b4, 10118, 14331);
+ /** Japanese JIS B3 media size: 364mm x 515mm (14.331" x 20.276") */
+ public static final MediaSize JIS_B3 =
+ new MediaSize("JIS_B3", "android",
+ R.string.mediaSize_japanese_jis_b3, 14331, 20276);
+ /** Japanese JIS B2 media size: 515mm x 728mm (20.276" x 28.661") */
+ public static final MediaSize JIS_B2 =
+ new MediaSize("JIS_B2", "android",
+ R.string.mediaSize_japanese_jis_b2, 20276, 28661);
+ /** Japanese JIS B1 media size: 728mm x 1030mm (28.661" x 40.551") */
+ public static final MediaSize JIS_B1 =
+ new MediaSize("JIS_B1", "android",
+ R.string.mediaSize_japanese_jis_b1, 28661, 40551);
+ /** Japanese JIS B0 media size: 1030mm x 1456mm (40.551" x 57.323") */
+ public static final MediaSize JIS_B0 =
+ new MediaSize("JIS_B0", "android",
+ R.string.mediaSize_japanese_jis_b0, 40551, 57323);
+
+ /** Japanese JIS Exec media size: 216mm x 330mm (8.504" x 12.992") */
+ public static final MediaSize JIS_EXEC =
+ new MediaSize("JIS_EXEC", "android",
+ R.string.mediaSize_japanese_jis_exec, 8504, 12992);
+
+ /** Japanese Chou4 media size: 90mm x 205mm (3.543" x 8.071") */
+ public static final MediaSize JPN_CHOU4 =
+ new MediaSize("JPN_CHOU4", "android",
+ R.string.mediaSize_japanese_chou4, 3543, 8071);
+ /** Japanese Chou3 media size: 120mm x 235mm (4.724" x 9.252") */
+ public static final MediaSize JPN_CHOU3 =
+ new MediaSize("JPN_CHOU3", "android",
+ R.string.mediaSize_japanese_chou3, 4724, 9252);
+ /** Japanese Chou2 media size: 111.1mm x 146mm (4.374" x 5.748") */
+ public static final MediaSize JPN_CHOU2 =
+ new MediaSize("JPN_CHOU2", "android",
+ R.string.mediaSize_japanese_chou2, 4374, 5748);
+
+ /** Japanese Hagaki media size: 100mm x 148mm (3.937" x 5.827") */
+ public static final MediaSize JPN_HAGAKI =
+ new MediaSize("JPN_HAGAKI", "android",
+ R.string.mediaSize_japanese_hagaki, 3937, 5827);
+ /** Japanese Oufuku media size: 148mm x 200mm (5.827" x 7.874") */
+ public static final MediaSize JPN_OUFUKU =
+ new MediaSize("JPN_OUFUKU", "android",
+ R.string.mediaSize_japanese_oufuku, 5827, 7874);
+
+ /** Japanese Kahu media size: 240mm x 322.1mm (9.449" x 12.681") */
+ public static final MediaSize JPN_KAHU =
+ new MediaSize("JPN_KAHU", "android",
+ R.string.mediaSize_japanese_kahu, 9449, 12681);
+ /** Japanese Kaku2 media size: 240mm x 332mm (9.449" x 13.071") */
+ public static final MediaSize JPN_KAKU2 =
+ new MediaSize("JPN_KAKU2", "android",
+ R.string.mediaSize_japanese_kaku2, 9449, 13071);
+
+ /** Japanese You4 media size: 105mm x 235mm (4.134" x 9.252") */
+ public static final MediaSize JPN_YOU4 =
+ new MediaSize("JPN_YOU4", "android",
+ R.string.mediaSize_japanese_you4, 4134, 9252);
private final String mId;
/**@hide */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c8312e3..6c6635d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4355,6 +4355,12 @@
public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
/**
+ * Specifies the package name currently configured to be the primary sms application
+ * @hide
+ */
+ public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
+
+ /**
* Name of a package that the current user has explicitly allowed to see all of that
* user's notifications.
*
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index ba6f1d4..30bb447 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -56,7 +56,7 @@
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getRepeatCount() == 0
&& MetaKeyKeyListener.getMetaState(buffer,
- MetaKeyKeyListener.META_SELECTING, event) != 0) {
+ MetaKeyKeyListener.META_SELECTING) != 0) {
return widget.showContextMenu();
}
}
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 63607fa..4fede32 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -75,7 +75,7 @@
}
// Alt+Backspace or Alt+ForwardDelete deletes the current line, if possible.
- if (getMetaState(content, META_ALT_ON, event) == 1) {
+ if (event.isAltPressed() || getMetaState(content, META_ALT_ON) == 1) {
if (deleteLine(view, content)) {
return true;
}
diff --git a/core/java/android/text/method/BaseMovementMethod.java b/core/java/android/text/method/BaseMovementMethod.java
index 155a2c4..113a4be 100644
--- a/core/java/android/text/method/BaseMovementMethod.java
+++ b/core/java/android/text/method/BaseMovementMethod.java
@@ -135,7 +135,7 @@
*/
protected int getMovementMetaState(Spannable buffer, KeyEvent event) {
// We ignore locked modifiers and SHIFT.
- int metaState = MetaKeyKeyListener.getMetaState(buffer, event)
+ int metaState = (event.getMetaState() | MetaKeyKeyListener.getMetaState(buffer))
& ~(MetaKeyKeyListener.META_ALT_LOCKED | MetaKeyKeyListener.META_SYM_LOCKED);
return KeyEvent.normalizeMetaState(metaState) & ~KeyEvent.META_SHIFT_MASK;
}
diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java
index bb8b0de..ce51fae 100644
--- a/core/java/android/text/method/DialerKeyListener.java
+++ b/core/java/android/text/method/DialerKeyListener.java
@@ -53,7 +53,7 @@
* from the KeyEvent.
*/
protected int lookup(KeyEvent event, Spannable content) {
- int meta = getMetaState(content, event);
+ int meta = event.getMetaState() | getMetaState(content);
int number = event.getNumber();
/*
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index e9db5fd..5ebb957 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -163,29 +163,6 @@
getActive(text, SELECTING, META_SELECTING, META_SELECTING);
}
- /**
- * Gets the state of the meta keys for a specific key event.
- *
- * For input devices that use toggled key modifiers, the `toggled' state
- * is stored into the text buffer. This method retrieves the meta state
- * for this event, accounting for the stored state. If the event has been
- * created by a device that does not support toggled key modifiers, like
- * a virtual device for example, the stored state is ignored.
- *
- * @param text the buffer in which the meta key would have been pressed.
- * @param event the event for which to evaluate the meta state.
- * @return an integer in which each bit set to one represents a pressed
- * or locked meta key.
- */
- public static final int getMetaState(final CharSequence text, final KeyEvent event) {
- int metaState = event.getMetaState();
- if (event.getKeyCharacterMap().getModifierBehavior()
- == KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED) {
- metaState |= getMetaState(text);
- }
- return metaState;
- }
-
// As META_SELECTING is @hide we should not mention it in public comments, hence the
// omission in @param meta
/**
@@ -215,37 +192,6 @@
}
}
- /**
- * Gets the state of a particular meta key to use with a particular key event.
- *
- * If the key event has been created by a device that does not support toggled
- * key modifiers, like a virtual keyboard for example, only the meta state in
- * the key event is considered.
- *
- * @param meta META_SHIFT_ON, META_ALT_ON, META_SYM_ON
- * @param text the buffer in which the meta key would have been pressed.
- * @param event the event for which to evaluate the meta state.
- * @return 0 if inactive, 1 if active, 2 if locked.
- */
- public static final int getMetaState(final CharSequence text, final int meta,
- final KeyEvent event) {
- int metaState = event.getMetaState();
- if (event.getKeyCharacterMap().getModifierBehavior()
- == KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED) {
- metaState |= getMetaState(text);
- }
- if (META_SELECTING == meta) {
- // #getMetaState(long, int) does not support META_SELECTING, but we want the same
- // behavior as #getMetaState(CharSequence, int) so we need to do it here
- if ((metaState & META_SELECTING) != 0) {
- // META_SELECTING is only ever set to PRESSED and can't be LOCKED, so return 1
- return 1;
- }
- return 0;
- }
- return getMetaState(metaState, meta);
- }
-
private static int getActive(CharSequence text, Object meta,
int on, int lock) {
if (!(text instanceof Spanned)) {
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index 988d566..5d4c732 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -41,7 +41,7 @@
protected abstract char[] getAcceptedChars();
protected int lookup(KeyEvent event, Spannable content) {
- return event.getMatch(getAcceptedChars(), getMetaState(content, event));
+ return event.getMatch(getAcceptedChars(), event.getMetaState() | getMetaState(content));
}
public CharSequence filter(CharSequence source, int start, int end,
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 0bd46bc..98316ae 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -108,7 +108,7 @@
// QWERTY keyboard normal case
- int i = event.getUnicodeChar(getMetaState(content, event));
+ int i = event.getUnicodeChar(event.getMetaState() | getMetaState(content));
if (!mFullKeyboard) {
int count = event.getRepeatCount();
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index 4cc2c42..5f948bd 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -41,7 +41,6 @@
private static boolean DBG = Transition.DBG && false;
private static final String LOG_TAG = "Fade";
- private static final String PROPNAME_ALPHA = "android:fade:alpha";
private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";
@@ -90,7 +89,8 @@
}
return null;
}
- final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
+ final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "transitionAlpha", startAlpha,
+ endAlpha);
if (DBG) {
Log.d(LOG_TAG, "Created animator " + anim);
}
@@ -102,8 +102,6 @@
}
private void captureValues(TransitionValues transitionValues) {
- float alpha = transitionValues.view.getAlpha();
- transitionValues.values.put(PROPNAME_ALPHA, alpha);
int[] loc = new int[2];
transitionValues.view.getLocationOnScreen(loc);
transitionValues.values.put(PROPNAME_SCREEN_X, loc[0]);
@@ -116,29 +114,6 @@
captureValues(transitionValues);
}
-
- @Override
- public void captureEndValues(TransitionValues transitionValues) {
- super.captureEndValues(transitionValues);
- }
-
- @Override
- public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
- TransitionValues endValues) {
- Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
- if (animator == null && startValues != null && endValues != null) {
- boolean endVisible = isVisible(endValues);
- final View endView = endValues.view;
- float endAlpha = endView.getAlpha();
- float startAlpha = (Float) startValues.values.get(PROPNAME_ALPHA);
- if ((endVisible && startAlpha < endAlpha && (mFadingMode & Fade.IN) != 0) ||
- (!endVisible && startAlpha > endAlpha && (mFadingMode & Fade.OUT) != 0)) {
- animator = createAnimation(endView, startAlpha, endAlpha, null);
- }
- }
- return animator;
- }
-
@Override
public Animator onAppear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
@@ -152,40 +127,37 @@
Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
}
- // if alpha < 1, just fade it in from the current value
- if (endView.getAlpha() == 1.0f) {
- endView.setAlpha(0);
- TransitionListener transitionListener = new TransitionListenerAdapter() {
- boolean mCanceled = false;
- float mPausedAlpha;
+ endView.setTransitionAlpha(0);
+ TransitionListener transitionListener = new TransitionListenerAdapter() {
+ boolean mCanceled = false;
+ float mPausedAlpha;
- @Override
- public void onTransitionCancel(Transition transition) {
- endView.setAlpha(1);
- mCanceled = true;
- }
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ endView.setTransitionAlpha(1);
+ mCanceled = true;
+ }
- @Override
- public void onTransitionEnd(Transition transition) {
- if (!mCanceled) {
- endView.setAlpha(1);
- }
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ if (!mCanceled) {
+ endView.setTransitionAlpha(1);
}
+ }
- @Override
- public void onTransitionPause(Transition transition) {
- mPausedAlpha = endView.getAlpha();
- endView.setAlpha(1);
- }
+ @Override
+ public void onTransitionPause(Transition transition) {
+ mPausedAlpha = endView.getTransitionAlpha();
+ endView.setTransitionAlpha(1);
+ }
- @Override
- public void onTransitionResume(Transition transition) {
- endView.setAlpha(mPausedAlpha);
- }
- };
- addListener(transitionListener);
- }
- return createAnimation(endView, endView.getAlpha(), 1, null);
+ @Override
+ public void onTransitionResume(Transition transition) {
+ endView.setTransitionAlpha(mPausedAlpha);
+ }
+ };
+ addListener(transitionListener);
+ return createAnimation(endView, 0, 1, null);
}
@Override
@@ -236,7 +208,7 @@
overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
sceneRoot.getOverlay().add(overlayView);
// TODO: add automatic facility to Visibility superclass for keeping views around
- final float startAlpha = view.getAlpha();
+ final float startAlpha = 1;
float endAlpha = 0;
final View finalView = view;
final View finalOverlayView = overlayView;
@@ -245,7 +217,7 @@
final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- finalView.setAlpha(startAlpha);
+ finalView.setTransitionAlpha(startAlpha);
// TODO: restore view offset from overlay repositioning
if (finalViewToKeep != null) {
finalViewToKeep.setVisibility(finalVisibility);
@@ -276,7 +248,7 @@
// VISIBLE for the duration of the transition
viewToKeep.setVisibility((View.VISIBLE));
// TODO: add automatic facility to Visibility superclass for keeping views around
- final float startAlpha = view.getAlpha();
+ final float startAlpha = 1;
float endAlpha = 0;
final View finalView = view;
final View finalOverlayView = overlayView;
@@ -291,8 +263,8 @@
if (finalViewToKeep != null && !mCanceled) {
finalViewToKeep.setVisibility(finalVisibility);
}
- mPausedAlpha = finalView.getAlpha();
- finalView.setAlpha(startAlpha);
+ mPausedAlpha = finalView.getTransitionAlpha();
+ finalView.setTransitionAlpha(startAlpha);
}
@Override
@@ -300,21 +272,21 @@
if (finalViewToKeep != null && !mCanceled) {
finalViewToKeep.setVisibility(View.VISIBLE);
}
- finalView.setAlpha(mPausedAlpha);
+ finalView.setTransitionAlpha(mPausedAlpha);
}
@Override
public void onAnimationCancel(Animator animation) {
mCanceled = true;
if (mPausedAlpha >= 0) {
- finalView.setAlpha(mPausedAlpha);
+ finalView.setTransitionAlpha(mPausedAlpha);
}
}
@Override
public void onAnimationEnd(Animator animation) {
if (!mCanceled) {
- finalView.setAlpha(startAlpha);
+ finalView.setTransitionAlpha(startAlpha);
}
// TODO: restore view offset from overlay repositioning
if (finalViewToKeep != null && !mCanceled) {
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 60b4708..4a99153 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -353,7 +353,7 @@
if (endValues.viewValues.get(view) != null) {
end = endValues.viewValues.get(view);
endCopy.remove(view);
- } else {
+ } else if (id != View.NO_ID) {
end = endValues.idValues.get(id);
View removeView = null;
for (View viewToRemove : endCopy.keySet()) {
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index f72b36e..6fdd309 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -354,7 +354,7 @@
clone.mTransitions = new ArrayList<Transition>();
int numTransitions = mTransitions.size();
for (int i = 0; i < numTransitions; ++i) {
- clone.mTransitions.add((Transition) mTransitions.get(i).clone());
+ clone.addTransition((Transition) mTransitions.get(i).clone());
}
return clone;
}
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index a0d39ca..f36c78f 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -130,7 +130,7 @@
private float mFocusX;
private float mFocusY;
- private boolean mDoubleTapScales;
+ private boolean mQuickScaleEnabled;
private float mCurrSpan;
private float mPrevSpan;
@@ -307,7 +307,7 @@
final int action = event.getActionMasked();
// Forward the event to check for double tap gesture
- if (mDoubleTapScales) {
+ if (mQuickScaleEnabled) {
mGestureDetector.onTouchEvent(event);
}
@@ -456,8 +456,8 @@
* @param scales true to enable quick scaling, false to disable
*/
public void setQuickScaleEnabled(boolean scales) {
- mDoubleTapScales = scales;
- if (mDoubleTapScales && mGestureDetector == null) {
+ mQuickScaleEnabled = scales;
+ if (mQuickScaleEnabled && mGestureDetector == null) {
GestureDetector.SimpleOnGestureListener gestureListener =
new GestureDetector.SimpleOnGestureListener() {
@Override
@@ -472,6 +472,14 @@
}
}
+ /**
+ * Return whether the quick scale gesture, in which the user performs a double tap followed by a
+ * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}.
+ */
+ public boolean isQuickScaleEnabled() {
+ return mQuickScaleEnabled;
+ }
+
/**
* Returns {@code true} if a scale gesture is in progress.
*/
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a5db6ee..4680e76 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2894,6 +2894,13 @@
*/
@ViewDebug.ExportedProperty
float mAlpha = 1f;
+
+ /**
+ * The opacity of the view as manipulated by the Fade transition. This is a hidden
+ * property only used by transitions, which is composited with the other alpha
+ * values to calculate the final visual alpha value.
+ */
+ float mTransitionAlpha = 1f;
}
TransformationInfo mTransformationInfo;
@@ -5335,7 +5342,8 @@
View view = (View) current;
// We have attach info so this view is attached and there is no
// need to check whether we reach to ViewRootImpl on the way up.
- if (view.getAlpha() <= 0 || view.getVisibility() != VISIBLE) {
+ if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 ||
+ view.getVisibility() != VISIBLE) {
return false;
}
current = view.mParent;
@@ -9786,7 +9794,7 @@
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
if (mDisplayList != null) {
- mDisplayList.setAlpha(alpha);
+ mDisplayList.setAlpha(getFinalAlpha());
}
}
}
@@ -9813,7 +9821,7 @@
} else {
mPrivateFlags &= ~PFLAG_ALPHA_SET;
if (mDisplayList != null) {
- mDisplayList.setAlpha(alpha);
+ mDisplayList.setAlpha(getFinalAlpha());
}
}
}
@@ -9821,6 +9829,51 @@
}
/**
+ * This property is hidden and intended only for use by the Fade transition, which
+ * animates it to produce a visual translucency that does not side-effect (or get
+ * affected by) the real alpha property. This value is composited with the other
+ * alpha value (and the AlphaAnimation value, when that is present) to produce
+ * a final visual translucency result, which is what is passed into the DisplayList.
+ *
+ * @hide
+ */
+ public void setTransitionAlpha(float alpha) {
+ ensureTransformationInfo();
+ if (mTransformationInfo.mTransitionAlpha != alpha) {
+ mTransformationInfo.mTransitionAlpha = alpha;
+ mPrivateFlags &= ~PFLAG_ALPHA_SET;
+ invalidateViewProperty(true, false);
+ if (mDisplayList != null) {
+ mDisplayList.setAlpha(getFinalAlpha());
+ }
+ }
+ }
+
+ /**
+ * Calculates the visual alpha of this view, which is a combination of the actual
+ * alpha value and the transitionAlpha value (if set).
+ */
+ private float getFinalAlpha() {
+ if (mTransformationInfo != null) {
+ return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha;
+ }
+ return 1;
+ }
+
+ /**
+ * This property is hidden and intended only for use by the Fade transition, which
+ * animates it to produce a visual translucency that does not side-effect (or get
+ * affected by) the real alpha property. This value is composited with the other
+ * alpha value (and the AlphaAnimation value, when that is present) to produce
+ * a final visual translucency result, which is what is passed into the DisplayList.
+ *
+ * @hide
+ */
+ public float getTransitionAlpha() {
+ return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1;
+ }
+
+ /**
* Top position of this view relative to its parent.
*
* @return The top of this view, in pixels.
@@ -10913,7 +10966,7 @@
@ViewDebug.ExportedProperty(category = "drawing")
public boolean isOpaque() {
return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK &&
- ((mTransformationInfo != null ? mTransformationInfo.mAlpha : 1.0f) >= 1.0f);
+ getFinalAlpha() >= 1.0f;
}
/**
@@ -13868,7 +13921,7 @@
}
}
if (mTransformationInfo != null) {
- alpha *= mTransformationInfo.mAlpha;
+ alpha *= getFinalAlpha();
if (alpha < 1) {
final int multipliedAlpha = (int) (255 * alpha);
if (onSetAlpha(multipliedAlpha)) {
@@ -14057,8 +14110,8 @@
}
}
- float alpha = useDisplayListProperties ? 1 : getAlpha();
- if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() ||
+ float alpha = useDisplayListProperties ? 1 : (getAlpha() * getTransitionAlpha());
+ if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() ||
(mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) {
if (transformToApply != null || !childHasIdentityMatrix) {
int transX = 0;
@@ -14115,7 +14168,7 @@
layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
}
if (useDisplayListProperties) {
- displayList.setAlpha(alpha * getAlpha());
+ displayList.setAlpha(alpha * getAlpha() * getTransitionAlpha());
} else if (layerType == LAYER_TYPE_NONE) {
final int scrollX = hasDisplayList ? 0 : sx;
final int scrollY = hasDisplayList ? 0 : sy;
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index ad8b51d..f9298ea 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -990,10 +990,10 @@
mStart = false;
if (mDataCopy != null) {
mData = mDataCopy;
+ mAccess.mData.clear();
+ mAccess.mSize = 0;
}
mDataCopy = null;
- mAccess.mData.clear();
- mAccess.mSize = 0;
}
int size() {
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 21b0578..aa57423 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -238,9 +238,10 @@
* @param totalQuota The total quota for all origins, in bytes
* @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
* must be used to inform the WebView of the new quota.
+ * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+ * Management API.
*/
- // Note that the callback must always be executed at some point to ensure
- // that the sleeping WebCore thread is woken up.
+ @Deprecated
public void onExceededDatabaseQuota(String url, String databaseIdentifier,
long quota, long estimatedDatabaseSize, long totalQuota,
WebStorage.QuotaUpdater quotaUpdater) {
@@ -263,9 +264,10 @@
* @param quota the current maximum Application Cache size, in bytes
* @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
* must be used to inform the WebView of the new quota.
+ * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+ * Management API.
*/
- // Note that the callback must always be executed at some point to ensure
- // that the sleeping WebCore thread is woken up.
+ @Deprecated
public void onReachedMaxAppCacheSize(long requiredStorage, long quota,
WebStorage.QuotaUpdater quotaUpdater) {
quotaUpdater.updateQuota(quota);
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 7a38a16..98ef66e 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -33,14 +33,17 @@
/**
* Enum for controlling the layout of html.
* <ul>
- * <li>NORMAL means no rendering changes.</li>
+ * <li>NORMAL means no rendering changes. This is the recommended choice for maximum
+ * compatibility across different platforms and Android versions.</li>
* <li>SINGLE_COLUMN moves all content into one column that is the width of the
* view.</li>
- * <li>NARROW_COLUMNS makes all columns no wider than the screen if possible.</li>
+ * <li>NARROW_COLUMNS makes all columns no wider than the screen if possible. Only use
+ * this for API levels prior to {@link android.os.Build.VERSION_CODES#KITKAT}.</li>
* <li>TEXT_AUTOSIZING boosts font size of paragraphs based on heuristics to make
* the text readable when viewing a wide-viewport layout in the overview mode.
* It is recommended to enable zoom support {@link #setSupportZoom} when
- * using this mode.</li>
+ * using this mode. Supported from API level
+ * {@link android.os.Build.VERSION_CODES#KITKAT}</li>
* </ul>
*/
// XXX: These must match LayoutAlgorithm in Settings.h in WebCore.
@@ -51,10 +54,11 @@
*/
@Deprecated
SINGLE_COLUMN,
- NARROW_COLUMNS,
/**
- * @hide
+ * @deprecated This algorithm is now obsolete.
*/
+ @Deprecated
+ NARROW_COLUMNS,
TEXT_AUTOSIZING
}
@@ -510,7 +514,10 @@
* and {@link #setUseWideViewPort} can be used.
*
* @param zoom the zoom density
+ * @deprecated This method is no longer supported, see the function documentation for
+ * recommended alternatives.
*/
+ @Deprecated
public void setDefaultZoom(ZoomDensity zoom) {
throw new MustOverrideException();
}
@@ -523,6 +530,7 @@
*
* @return the zoom density
* @see #setDefaultZoom
+ * @deprecated Will only return the default value.
*/
public ZoomDensity getDefaultZoom() {
throw new MustOverrideException();
@@ -1059,10 +1067,13 @@
*
* @param databasePath a path to the directory where databases should be
* saved.
+ * @deprecated Database paths are managed by the implementation and calling this method
+ * will have no effect.
*/
// This will update WebCore when the Sync runs in the C++ side.
// Note that the WebCore Database Tracker only allows the path to be set
// once.
+ @Deprecated
public synchronized void setDatabasePath(String databasePath) {
throw new MustOverrideException();
}
@@ -1161,7 +1172,9 @@
*
* @return the String path to the database storage API databases
* @see #setDatabasePath
+ * @deprecated Database paths are managed by the implementation this method is obsolete.
*/
+ @Deprecated
public synchronized String getDatabasePath() {
throw new MustOverrideException();
}
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 7d9373c..3bfe9cf 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -41,12 +41,9 @@
* See
* {@link WebChromeClient#onExceededDatabaseQuota} and
* {@link WebChromeClient#onReachedMaxAppCacheSize}.
+ * @deprecated This class is obsolete and no longer used.
*/
- // We primarily want this to allow us to call back the sleeping WebCore
- // thread from outside the WebViewCore class (as the native call is
- // private). It is imperative that the setDatabaseQuota method is
- // executed after a decision to either allow or deny new quota is made,
- // otherwise the WebCore thread will remain asleep.
+ @Deprecated
public interface QuotaUpdater {
/**
* Provides a new quota, specified in bytes.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 15331dc..20fb1a7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1058,9 +1058,20 @@
* {@link android.os.Build.VERSION_CODES#HONEYCOMB} and
* {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} inclusive, the
* picture does not include fixed position elements or scrollable divs.
+ * <p>
+ * Note that from {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} the returned picture
+ * should only be drawn into bitmap-backed Canvas - using any other type of Canvas will involve
+ * additional conversion at a cost in memory and performance. Also the
+ * {@link android.graphics.Picture#createFromStream} and
+ * {@link android.graphics.Picture#writeToStream} methods are not supported on the
+ * returned object.
+ *
+ * @deprecated Use {@link #onDraw} to obtain a bitmap snapshot of the WebView, or
+ * {@link #saveWebArchive} to save the content to a file.
*
* @return a picture that captures the current contents of this WebView
*/
+ @Deprecated
public Picture capturePicture() {
checkThread();
if (DebugFlags.TRACE_API) Log.d(LOGTAG, "capturePicture");
@@ -1342,7 +1353,10 @@
/**
* Informs this WebView that memory is low so that it can free any available
* memory.
+ * @deprecated Memory caches are automatically dropped when no longer needed, and in response
+ * to system memory pressure.
*/
+ @Deprecated
public void freeMemory() {
checkThread();
if (DebugFlags.TRACE_API) Log.d(LOGTAG, "freeMemory");
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index de2be75..0957ab4 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -391,7 +391,7 @@
mWeekSeperatorLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
UNSCALED_WEEK_SEPARATOR_LINE_WIDTH, displayMetrics);
- LayoutInflater layoutInflater = (LayoutInflater) mContext
+ LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Service.LAYOUT_INFLATER_SERVICE);
View content = layoutInflater.inflate(R.layout.calendar_view, null, false);
addView(content);
@@ -874,7 +874,6 @@
}
mFirstDayOfWeek = firstDayOfWeek;
mAdapter.init();
- mAdapter.notifyDataSetChanged();
setUpHeader();
}
@@ -937,7 +936,7 @@
}
private void updateDateTextSize() {
- TypedArray dateTextAppearance = getContext().obtainStyledAttributes(
+ TypedArray dateTextAppearance = mContext.obtainStyledAttributes(
mDateTextAppearanceResId, R.styleable.TextAppearance);
mDateTextSize = dateTextAppearance.getDimensionPixelSize(
R.styleable.TextAppearance_textSize, DEFAULT_DATE_TEXT_SIZE);
@@ -1004,7 +1003,7 @@
*/
private void setUpAdapter() {
if (mAdapter == null) {
- mAdapter = new WeeksAdapter(getContext());
+ mAdapter = new WeeksAdapter();
mAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
@@ -1333,19 +1332,16 @@
* </p>
*/
private class WeeksAdapter extends BaseAdapter implements OnTouchListener {
+ private final Calendar mSelectedDate = Calendar.getInstance();
+ private final GestureDetector mGestureDetector;
private int mSelectedWeek;
- private GestureDetector mGestureDetector;
-
private int mFocusedMonth;
- private final Calendar mSelectedDate = Calendar.getInstance();
-
private int mTotalWeekCount;
- public WeeksAdapter(Context context) {
- mContext = context;
+ public WeeksAdapter() {
mGestureDetector = new GestureDetector(mContext, new CalendarGestureListener());
init();
}
@@ -1360,6 +1356,7 @@
|| mMaxDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek) {
mTotalWeekCount++;
}
+ notifyDataSetChanged();
}
/**
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 19cc3c2..e4956dd 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1099,6 +1099,16 @@
}
@Override
+ public int computeVerticalScrollOffset() {
+ return mCurrentScrollOffset;
+ }
+
+ @Override
+ public int computeVerticalScrollRange() {
+ return mSelectorIndices.length * mSelectorElementHeight;
+ }
+
+ @Override
public int getSolidColor() {
return mSolidColor;
}
diff --git a/core/java/com/android/internal/app/IProcessStats.aidl b/core/java/com/android/internal/app/IProcessStats.aidl
index 047424d..6fadf2f 100644
--- a/core/java/com/android/internal/app/IProcessStats.aidl
+++ b/core/java/com/android/internal/app/IProcessStats.aidl
@@ -22,5 +22,6 @@
interface IProcessStats {
byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
+ ParcelFileDescriptor getStatsOverTime(long minTime);
int getCurrentMemoryState();
}
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index d3fe34e..1475e2c 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -166,7 +166,7 @@
static final String CSV_SEP = "\t";
// Current version of the parcel format.
- private static final int PARCEL_VERSION = 11;
+ private static final int PARCEL_VERSION = 12;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0x50535453;
@@ -1076,10 +1076,8 @@
return table;
}
- private void writeCompactedLongArray(Parcel out, long[] array) {
- final int N = array.length;
- out.writeInt(N);
- for (int i=0; i<N; i++) {
+ private void writeCompactedLongArray(Parcel out, long[] array, int num) {
+ for (int i=0; i<num; i++) {
long val = array[i];
if (val < 0) {
Slog.w(TAG, "Time val negative: " + val);
@@ -1096,16 +1094,17 @@
}
}
- private void readCompactedLongArray(Parcel in, int version, long[] array) {
+ private void readCompactedLongArray(Parcel in, int version, long[] array, int num) {
if (version <= 10) {
in.readLongArray(array);
return;
}
- final int N = in.readInt();
- if (N != array.length) {
- throw new RuntimeException("bad array lengths");
+ final int alen = array.length;
+ if (num > alen) {
+ throw new RuntimeException("bad array lengths: got " + num + " array is " + alen);
}
- for (int i=0; i<N; i++) {
+ int i;
+ for (i=0; i<num; i++) {
int val = in.readInt();
if (val >= 0) {
array[i] = val;
@@ -1114,6 +1113,10 @@
array[i] = (((long)~val)<<32) | bottom;
}
}
+ while (i < alen) {
+ array[i] = 0;
+ i++;
+ }
}
private void writeCommonString(Parcel out, String name) {
@@ -1203,19 +1206,17 @@
out.writeInt(mLongs.size());
out.writeInt(mNextLong);
for (int i=0; i<(mLongs.size()-1); i++) {
- writeCompactedLongArray(out, mLongs.get(i));
+ long[] array = mLongs.get(i);
+ writeCompactedLongArray(out, array, array.length);
}
long[] lastLongs = mLongs.get(mLongs.size() - 1);
- for (int i=0; i<mNextLong; i++) {
- out.writeLong(lastLongs[i]);
- if (DEBUG) Slog.d(TAG, "Writing last long #" + i + ": " + lastLongs[i]);
- }
+ writeCompactedLongArray(out, lastLongs, mNextLong);
if (mMemFactor != STATE_NOTHING) {
mMemFactorDurations[mMemFactor] += now - mStartTime;
mStartTime = now;
}
- writeCompactedLongArray(out, mMemFactorDurations);
+ writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length);
out.writeInt(NPROC);
for (int ip=0; ip<NPROC; ip++) {
@@ -1276,23 +1277,25 @@
return true;
}
- static byte[] readFully(InputStream stream) throws IOException {
+ static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
int pos = 0;
- int avail = stream.available();
- byte[] data = new byte[avail];
+ final int initialAvail = stream.available();
+ byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
while (true) {
int amt = stream.read(data, pos, data.length-pos);
- //Log.i("foo", "Read " + amt + " bytes at " + pos
- // + " of avail " + data.length);
- if (amt <= 0) {
- //Log.i("foo", "**** FINISHED READING: pos=" + pos
- // + " len=" + data.length);
+ if (DEBUG) Slog.i("foo", "Read " + amt + " bytes at " + pos
+ + " of avail " + data.length);
+ if (amt < 0) {
+ if (DEBUG) Slog.i("foo", "**** FINISHED READING: pos=" + pos
+ + " len=" + data.length);
+ outLen[0] = pos;
return data;
}
pos += amt;
- avail = stream.available();
- if (avail > data.length-pos) {
- byte[] newData = new byte[pos+avail];
+ if (pos >= data.length) {
+ byte[] newData = new byte[pos+16384];
+ if (DEBUG) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
+ + newData.length);
System.arraycopy(data, 0, newData, 0, pos);
data = newData;
}
@@ -1301,9 +1304,10 @@
public void read(InputStream stream) {
try {
- byte[] raw = readFully(stream);
+ int[] len = new int[1];
+ byte[] raw = readFully(stream, len);
Parcel in = Parcel.obtain();
- in.unmarshall(raw, 0, raw.length);
+ in.unmarshall(raw, 0, len[0]);
in.setDataPosition(0);
stream.close();
@@ -1358,17 +1362,14 @@
while (i >= mLongs.size()) {
mLongs.add(new long[LONGS_SIZE]);
}
- readCompactedLongArray(in, version, mLongs.get(i));
+ readCompactedLongArray(in, version, mLongs.get(i), LONGS_SIZE);
}
long[] longs = new long[LONGS_SIZE];
mNextLong = NEXTLONG;
- for (int i=0; i<NEXTLONG; i++) {
- longs[i] = in.readLong();
- if (DEBUG) Slog.d(TAG, "Reading last long #" + i + ": " + longs[i]);
- }
+ readCompactedLongArray(in, version, longs, NEXTLONG);
mLongs.add(longs);
- readCompactedLongArray(in, version, mMemFactorDurations);
+ readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length);
int NPROC = in.readInt();
if (NPROC < 0) {
@@ -1669,7 +1670,8 @@
return ss;
}
- public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpAll) {
+ public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
+ boolean dumpAll) {
long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
mStartTime, now);
ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
@@ -1693,7 +1695,7 @@
pw.print(" * "); pw.print(pkgName); pw.print(" / ");
UserHandle.formatUid(pw, uid); pw.println(":");
}
- if (dumpAll) {
+ if (!dumpSummary || dumpAll) {
for (int iproc=0; iproc<NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
pw.print(" Process ");
@@ -1730,16 +1732,16 @@
ServiceState svc = pkgState.mServices.valueAt(isvc);
dumpServiceStats(pw, " ", " ", " ", "Running", svc,
svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState,
- svc.mRunStartTime, now, totalTime, dumpAll);
+ svc.mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
dumpServiceStats(pw, " ", " ", " ", "Started", svc,
svc.mStartedCount, ServiceState.SERVICE_STARTED, svc.mStartedState,
- svc.mStartedStartTime, now, totalTime, dumpAll);
+ svc.mStartedStartTime, now, totalTime, !dumpSummary || dumpAll);
dumpServiceStats(pw, " ", " ", " ", "Bound", svc,
svc.mBoundCount, ServiceState.SERVICE_BOUND, svc.mBoundState,
- svc.mBoundStartTime, now, totalTime, dumpAll);
+ svc.mBoundStartTime, now, totalTime, !dumpSummary || dumpAll);
dumpServiceStats(pw, " ", " ", " ", "Executing", svc,
svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState,
- svc.mExecStartTime, now, totalTime, dumpAll);
+ svc.mExecStartTime, now, totalTime, !dumpSummary || dumpAll);
if (dumpAll) {
pw.print(" mActive="); pw.println(svc.mActive);
}
@@ -1783,8 +1785,12 @@
}
pw.println();
- pw.println("Summary:");
- dumpSummaryLocked(pw, reqPackage, now);
+ if (dumpSummary) {
+ pw.println("Summary:");
+ dumpSummaryLocked(pw, reqPackage, now);
+ } else {
+ dumpTotalsLocked(pw, now);
+ }
} else {
pw.println();
dumpTotalsLocked(pw, now);
@@ -2514,7 +2520,7 @@
private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList, int index) {
ProcessState proc = pkgList.valueAt(index);
if (mDead && proc.mCommonProcess != proc) {
- // Somehow we try to continue to use a process state that is dead, because
+ // Somehow we are contining to use a process state that is dead, because
// it was not being told it was active during the last commit. We can recover
// from this by generating a fresh new state, but this is bad because we
// are losing whatever data we had in the old process state.
@@ -2529,7 +2535,7 @@
PackageState pkg = mStats.mPackages.get(pkgList.keyAt(index), proc.mUid);
if (pkg == null) {
throw new IllegalStateException("No existing package "
- + pkgList.keyAt(index) + " for multi-proc" + proc.mName);
+ + pkgList.keyAt(index) + " for multi-proc " + proc.mName);
}
proc = pkg.mProcesses.get(proc.mName);
if (proc == null) {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 969c94ba..7efcb6e 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1639,6 +1639,8 @@
@Override
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+ TransitionManager.beginDelayedTransition(ActionBarView.this, sTransition);
+
mExpandedActionView = item.getActionView();
mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources()));
mCurrentExpandedItem = item;
@@ -1666,6 +1668,8 @@
@Override
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+ TransitionManager.beginDelayedTransition(ActionBarView.this, sTransition);
+
// Do this before detaching the actionview from the hierarchy, in case
// it needs to dismiss the soft keyboard, etc.
if (mExpandedActionView instanceof CollapsibleActionView) {
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index f9bb233..9c20de2 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -3,6 +3,7 @@
#include "BitmapFactory.h"
#include "NinePatchPeeker.h"
#include "SkData.h"
+#include "SkFrontBufferedStream.h"
#include "SkImageDecoder.h"
#include "SkImageRef_ashmem.h"
#include "SkImageRef_GlobalPool.h"
@@ -120,7 +121,7 @@
}
}
-static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
+static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStreamRewindable* stream,
int sampleSize, bool ditherImage) {
SkImageRef* pr;
@@ -465,13 +466,17 @@
jobject padding, jobject options) {
jobject bitmap = NULL;
- SkAutoTUnref<SkStreamRewindable> stream(GetRewindableStream(env, is, storage));
+ SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
if (stream.get()) {
+ // Need to buffer enough input to be able to rewind as much as might be read by a decoder
+ // trying to determine the stream's format. Currently the most is 64, read by
+ // SkImageDecoder_libwebp.
+ // FIXME: Get this number from SkImageDecoder
+ SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(stream, 64));
+ SkASSERT(bufferedStream.get() != NULL);
// for now we don't allow purgeable with java inputstreams
- // FIXME: GetRewindableStream may have made a copy, in which case
- // purgeable should be allowed.
- bitmap = doDecode(env, stream, padding, options, false, false);
+ bitmap = doDecode(env, bufferedStream, padding, options, false, false);
}
return bitmap;
}
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index f773f59..da8f083 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -5,18 +5,12 @@
#include "SkStream.h"
#include "SkTypes.h"
#include "Utils.h"
-#include <androidfw/Asset.h>
-static jmethodID gInputStream_resetMethodID;
-static jmethodID gInputStream_markMethodID;
-static jmethodID gInputStream_markSupportedMethodID;
static jmethodID gInputStream_readMethodID;
static jmethodID gInputStream_skipMethodID;
-class RewindableJavaStream;
-
/**
- * Non-rewindable wrapper for a Java InputStream.
+ * Wrapper for a Java InputStream.
*/
class JavaInputStreamAdaptor : public SkStream {
public:
@@ -64,25 +58,6 @@
}
private:
- // Does not override rewind, since a JavaInputStreamAdaptor's interface
- // does not support rewinding. RewindableJavaStream, which is a friend,
- // will be able to call this method to rewind.
- bool doRewind() {
- JNIEnv* env = fEnv;
-
- fBytesRead = 0;
- fIsAtEnd = false;
-
- env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- SkDebugf("------- reset threw an exception\n");
- return false;
- }
- return true;
- }
-
size_t doRead(void* buffer, size_t size) {
JNIEnv* env = fEnv;
size_t bytesRead = 0;
@@ -148,9 +123,6 @@
size_t fCapacity;
size_t fBytesRead;
bool fIsAtEnd;
-
- // Allows access to doRewind and fBytesRead.
- friend class RewindableJavaStream;
};
SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
@@ -190,123 +162,6 @@
return adaptor_to_mem_stream(adaptor.get());
}
-/**
- * Wrapper for a Java InputStream which is rewindable and
- * has a length.
- */
-class RewindableJavaStream : public SkStreamRewindable {
-public:
- // RewindableJavaStream takes ownership of adaptor.
- RewindableJavaStream(JavaInputStreamAdaptor* adaptor, size_t length)
- : fAdaptor(adaptor)
- , fLength(length) {
- SkASSERT(fAdaptor != NULL);
- }
-
- virtual ~RewindableJavaStream() {
- fAdaptor->unref();
- }
-
- virtual bool rewind() {
- return fAdaptor->doRewind();
- }
-
- virtual size_t read(void* buffer, size_t size) {
- return fAdaptor->read(buffer, size);
- }
-
- virtual bool isAtEnd() const {
- return fAdaptor->isAtEnd();
- }
-
- virtual size_t getLength() const {
- return fLength;
- }
-
- virtual bool hasLength() const {
- return true;
- }
-
- virtual SkStreamRewindable* duplicate() const {
- // Duplicating this stream requires rewinding and
- // reading, which modify this Stream (and could
- // fail, leaving this one invalid).
- SkASSERT(false);
- return NULL;
- }
-
-private:
- JavaInputStreamAdaptor* fAdaptor;
- const size_t fLength;
-};
-
-static jclass gByteArrayInputStream_Clazz;
-static jfieldID gCountField;
-static jfieldID gPosField;
-
-/**
- * If jstream is a ByteArrayInputStream, return its remaining length. Otherwise
- * return 0.
- */
-static size_t get_length_from_byte_array_stream(JNIEnv* env, jobject jstream) {
- if (env->IsInstanceOf(jstream, gByteArrayInputStream_Clazz)) {
- // Return the remaining length, to keep the same behavior of using the rest of the
- // stream.
- return env->GetIntField(jstream, gCountField) - env->GetIntField(jstream, gPosField);
- }
- return 0;
-}
-
-/**
- * If jstream is a class that has a length, return it. Otherwise
- * return 0.
- * Only checks for a set of subclasses.
- */
-static size_t get_length_if_supported(JNIEnv* env, jobject jstream) {
- size_t len = get_length_from_byte_array_stream(env, jstream);
- if (len > 0) {
- return len;
- }
- return 0;
-}
-
-SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream,
- jbyteArray storage) {
- SkAutoTUnref<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage));
- if (NULL == adaptor.get()) {
- return NULL;
- }
-
- const size_t length = get_length_if_supported(env, stream);
- if (length > 0 && env->CallBooleanMethod(stream, gInputStream_markSupportedMethodID)) {
- // Set the readLimit for mark to the end of the stream, so it can
- // be rewound regardless of how much has been read.
- env->CallVoidMethod(stream, gInputStream_markMethodID, length);
- // RewindableJavaStream will unref adaptor when it is destroyed.
- return new RewindableJavaStream(static_cast<JavaInputStreamAdaptor*>(adaptor.detach()),
- length);
- }
-
- return adaptor_to_mem_stream(adaptor.get());
-}
-
-static jclass gAssetInputStream_Clazz;
-static jmethodID gGetAssetIntMethodID;
-
-android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject jstream) {
- if (!env->IsInstanceOf(jstream, gAssetInputStream_Clazz)) {
- return NULL;
- }
-
- jint jasset = env->CallIntMethod(jstream, gGetAssetIntMethodID);
- android::Asset* a = reinterpret_cast<android::Asset*>(jasset);
- if (NULL == a) {
- jniThrowNullPointerException(env, "NULL native asset");
- return NULL;
- }
- return new android::AssetStreamAdaptor(a);
-}
-
///////////////////////////////////////////////////////////////////////////////
static jmethodID gOutputStream_writeMethodID;
@@ -382,13 +237,6 @@
return clazz;
}
-static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
- const char fieldname[], const char type[]) {
- jfieldID id = env->GetFieldID(clazz, fieldname, type);
- SkASSERT(!env->ExceptionCheck());
- return id;
-}
-
static jmethodID getMethodIDCheck(JNIEnv* env, jclass clazz,
const char methodname[], const char type[]) {
jmethodID id = env->GetMethodID(clazz, methodname, type);
@@ -398,25 +246,9 @@
int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env) {
jclass inputStream_Clazz = findClassCheck(env, "java/io/InputStream");
- gInputStream_resetMethodID = getMethodIDCheck(env, inputStream_Clazz, "reset", "()V");
- gInputStream_markMethodID = getMethodIDCheck(env, inputStream_Clazz, "mark", "(I)V");
- gInputStream_markSupportedMethodID = getMethodIDCheck(env, inputStream_Clazz, "markSupported", "()Z");
gInputStream_readMethodID = getMethodIDCheck(env, inputStream_Clazz, "read", "([BII)I");
gInputStream_skipMethodID = getMethodIDCheck(env, inputStream_Clazz, "skip", "(J)J");
- gByteArrayInputStream_Clazz = findClassCheck(env, "java/io/ByteArrayInputStream");
- // Ref gByteArrayInputStream_Clazz so we can continue to refer to it when
- // calling IsInstance.
- gByteArrayInputStream_Clazz = (jclass) env->NewGlobalRef(gByteArrayInputStream_Clazz);
- gCountField = getFieldIDCheck(env, gByteArrayInputStream_Clazz, "count", "I");
- gPosField = getFieldIDCheck(env, gByteArrayInputStream_Clazz, "pos", "I");
-
- gAssetInputStream_Clazz = findClassCheck(env, "android/content/res/AssetManager$AssetInputStream");
- // Ref gAssetInputStream_Clazz so we can continue to refer to it when
- // calling IsInstance.
- gAssetInputStream_Clazz = (jclass) env->NewGlobalRef(gAssetInputStream_Clazz);
- gGetAssetIntMethodID = getMethodIDCheck(env, gAssetInputStream_Clazz, "getAssetInt", "()I");
-
jclass outputStream_Clazz = findClassCheck(env, "java/io/OutputStream");
gOutputStream_writeMethodID = getMethodIDCheck(env, outputStream_Clazz, "write", "([BII)V");
gOutputStream_flushMethodID = getMethodIDCheck(env, outputStream_Clazz, "flush", "()V");
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
index fcc0c9a..ecd270f 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
@@ -4,10 +4,6 @@
//#include <android_runtime/AndroidRuntime.h>
#include "jni.h"
-namespace android {
- class AssetStreamAdaptor;
-}
-
class SkMemoryStream;
class SkStream;
class SkStreamRewindable;
@@ -15,6 +11,7 @@
/**
* Return an adaptor from a Java InputStream to an SkStream.
+ * Does not support rewind.
* @param env JNIEnv object.
* @param stream Pointer to Java InputStream.
* @param storage Java byte array for retrieving data from the
@@ -28,7 +25,7 @@
jbyteArray storage);
/**
- * Copy a Java InputStream.
+ * Copy a Java InputStream. The result will be rewindable.
* @param env JNIEnv object.
* @param stream Pointer to Java InputStream.
* @param storage Java byte array for retrieving data from the
@@ -39,32 +36,6 @@
SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
jbyteArray storage);
-/**
- * Get a rewindable stream from a Java InputStream.
- * @param env JNIEnv object.
- * @param stream Pointer to Java InputStream.
- * @param storage Java byte array for retrieving data from the
- * Java InputStream.
- * @return SkStreamRewindable Either a wrapper around the Java
- * InputStream, if possible, or a copy which is rewindable.
- * Since it may be a wrapper, must not be used after the
- * caller returns, like the result of CreateJavaInputStreamAdaptor.
- */
-SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream,
- jbyteArray storage);
-
-/**
- * If the Java InputStream is an AssetInputStream, return an adaptor.
- * This should not be used after the calling function returns, since
- * the caller may close the asset. Returns NULL if the stream is
- * not an AssetInputStream.
- * @param env JNIEnv object.
- * @param stream Pointer to Java InputStream.
- * @return AssetStreamAdaptor representing the InputStream, or NULL.
- * Must not be held onto.
- */
-android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject stream);
-
SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
jbyteArray storage);
#endif
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 2eae841..feb2dec 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -1,4 +1,5 @@
#include "ScopedLocalRef.h"
+#include "SkFrontBufferedStream.h"
#include "SkMovie.h"
#include "SkStream.h"
#include "GraphicsJNI.h"
@@ -81,23 +82,33 @@
c->drawBitmap(b, sx, sy, p);
}
+static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jint native_asset) {
+ android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
+ if (asset == NULL) return NULL;
+ SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset));
+ SkMovie* moov = SkMovie::DecodeStream(stream.get());
+ return create_jmovie(env, moov);
+}
+
static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
NPE_CHECK_RETURN_ZERO(env, istream);
- SkStreamRewindable* strm = CheckForAssetStream(env, istream);
- jbyteArray byteArray = NULL;
- ScopedLocalRef<jbyteArray> scoper(env, NULL);
- if (NULL == strm) {
- byteArray = env->NewByteArray(16*1024);
- scoper.reset(byteArray);
- strm = GetRewindableStream(env, istream, byteArray);
- }
+ jbyteArray byteArray = env->NewByteArray(16*1024);
+ ScopedLocalRef<jbyteArray> scoper(env, byteArray);
+ SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
if (NULL == strm) {
return 0;
}
- SkMovie* moov = SkMovie::DecodeStream(strm);
+ // Need to buffer enough input to be able to rewind as much as might be read by a decoder
+ // trying to determine the stream's format. The only decoder for movies is GIF, which
+ // will only read 6.
+ // FIXME: Get this number from SkImageDecoder
+ SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
+ SkASSERT(bufferedStream.get() != NULL);
+
+ SkMovie* moov = SkMovie::DecodeStream(bufferedStream);
strm->unref();
return create_jmovie(env, moov);
}
@@ -135,7 +146,9 @@
{ "setTime", "(I)Z", (void*)movie_setTime },
{ "draw", "(Landroid/graphics/Canvas;FFLandroid/graphics/Paint;)V",
(void*)movie_draw },
- { "decodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
+ { "nativeDecodeAsset", "(I)Landroid/graphics/Movie;",
+ (void*)movie_decodeAsset },
+ { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
(void*)movie_decodeStream },
{ "nativeDestructor","(I)V", (void*)movie_destructor },
{ "decodeByteArray", "([BII)Landroid/graphics/Movie;",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 499a930..6898ab0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1103,6 +1103,13 @@
android:description="@string/permdesc_use_sip"
android:label="@string/permlab_use_sip" />
+ <!-- Allows an application to request CallHandlerService implementations. -->
+ <permission android:name="android.permission.BIND_CALL_SERVICE"
+ android:permissionGroup="android.permission-group.PHONE_CALLS"
+ android:protectionLevel="system|signature"
+ android:description="@string/permdesc_bind_call_service"
+ android:label="@string/permlab_bind_call_service" />
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
<!-- ================================== -->
@@ -2100,6 +2107,13 @@
android:description="@string/permdesc_captureSecureVideoOutput"
android:protectionLevel="signature|system" />
+ <!--@hide Allows an application to know what content is playing and control its playback.
+ <p>Not for use by third-party applications due to privacy of media consumption</p> -->
+ <permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
+ android:label="@string/permlab_mediaContentControl"
+ android:description="@string/permdesc_mediaContentControl"
+ android:protectionLevel="signature|system" />
+
<!-- Required to be able to disable the device (very dangerous!).
<p>Not for use by third-party applications.. -->
<permission android:name="android.permission.BRICK"
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
index 584ce05..7f79718 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
index ed317f7..951be79 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
index 40bd746..47f7c29 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
index c49bc84..841c964 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
index 958d023..fd2b63a 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
index 3464f3d..4fa62d7 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
index 3464f3d..242cee9 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
index 5dc3673..3ffd433 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
index c0d8a3d..6065eb7 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
index a920132..63ec738 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
index f6a8b45..1d80d5c 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
index 18c527d..9aed106 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
index 478f2e7..c5e4694 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
index b0be28d..0fe4b14 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
index ec3c748..aaced6e 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
index a929e09..185f9f7 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
index 013ca85..5d695d9 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
index 7b0e089..de15a23 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
index 692d705..beda050 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
index 677069a..9206f57 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
index 677069a..bef235b 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
index 6b5fa5a..63204eb 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
index 6b5fa5a..7b79f3f 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..da023d3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..e9afcc9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
index 5654cd6..1a0bf0d 100644
--- a/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
index 5654cd6..e852a45 100644
--- a/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
index e20b02d..1a0bf0d 100644
--- a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
index e20b02d..c9e662d 100644
--- a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index 0c689ff..4e40eda 100644
--- a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index f3999204..f1b7036 100644
--- a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
index dc20a8d..f06d898 100644
--- a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
index 272a2a1..0638e58 100644
--- a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
index 84560c5..6d2a8a4 100644
--- a/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
index e101d50..bb43a46 100644
--- a/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
index ea54380..88717cc 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
index ea54380..c759ca4 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
index 6278eef..fe5850c 100644
--- a/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
index aadc6f8..b59edc8 100644
--- a/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
index 9389a08..2eaa6e1 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
index 1109c20..83b3315 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
index 3a8cebc..2b8541c 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
index e9f5f06..e51e72a 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
index eb7a1fd..1940216 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
index 7e4eb5e..c10b235 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
index 7e4eb5e..db9eab0 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
index 194f58e..45252b1 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
index 2a7d0d5..1090816 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
index dff7c00..a740800 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
index 70c705f..faa95fc 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
index 5985e3c..bc82b1a 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
index 2085290..ab3a79b 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
index 4b62750..9b169d4 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
index 000a9c4..29ebf09 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
index 4bc4a30..a703645 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
index dd14aec..42876ce 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
index 2f1f004..c8ffef4 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
index 4bea36b..8be8533 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
index 045dc9a..5e55f6b 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
index 045dc9a..791eda5 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
index 6c4aa16..646ed1c 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
index 6c4aa16..08ea670 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..d120ab1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..3226ab7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
index 6e77525..5f97f2b 100644
--- a/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
index 6e77525..b6427cc 100644
--- a/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
index 13cb131..5f97f2b 100644
--- a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
index 13cb131..779d10e 100644
--- a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index eee058f..a70615a 100644
--- a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index 1ac24be..e7dd785 100644
--- a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
index 2fa15e7..561ac55 100644
--- a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
index a964b22..05ffe3f 100644
--- a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
index b82d1ac..363531a 100644
--- a/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
index f9b5f64..d62c04b 100644
--- a/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
index 670dc2e..92ba340 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
index 670dc2e..e099458 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
index 155c4fc..cdb7b19 100644
--- a/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
index b1223fe..b27c88d 100644
--- a/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
index c85f135..ebb439d5 100644
--- a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
index 50461d2..c497bf1 100644
--- a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
index ce4b578..30b884e 100644
--- a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
index 8f03489..511f125 100644
--- a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
index a0d64a3..0544d32 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
index 930b5f2..8a751c3 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
index 930b5f2..4294246 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
index 60aede8..bda54ee 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
index 614d27a..812e1b5 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
index f402bd1..6a0ee8d 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
index 041e5cc..4bedd5c 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
index 0804faf..e711d9d 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
index c649599..4bdf427 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
index 149f90d..79567ad 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
index 4145493..65d472f 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
index 85253f7..614f428 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
index efd26b0..f80f9b3 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
index e2305cb..840967c 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
index 6643deb..d7f7ee4 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
index 9d16f321..a1b4e40 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
index 9d16f321..ba9f6a0 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
index fde3ac3..4afca86 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
index fde3ac3..eb79128 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..4baaed3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..5532e88
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
index e4b3393..e9e7c18 100644
--- a/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
index e4b3393..5326b45 100644
--- a/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
index ee5eb6f..e9e7c18 100644
--- a/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png b/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
index ee5eb6f..74e3843 100644
--- a/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index 75c5996..16c1e00 100644
--- a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index a2d6ca1..92a298b 100644
--- a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
index a3c7711..fe701d8 100644
--- a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
index 2a21210..efec27b 100644
--- a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
index aecf6bd..eb44f17 100644
--- a/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
index 3273a22..dfceeed 100644
--- a/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
index 4acb32b..64a2e52 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
index 4acb32b..5110439 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
index e862cb1..1df4a4d 100644
--- a/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
index f1eb673..574dbef 100644
--- a/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
index a54cfbf3..5ba273a 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
index 5afea71..32942b9 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
index f4f58b7..70ee78f 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
index c270562..5bd562e 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
index e3d3eb1..e05017c 100644
--- a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
index 19706e0..a476b99 100644
--- a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
index af8eebb..cfa776c 100644
--- a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
index 9bc460f..181f0a5 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
index 96c63b1..536c618 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
index de76d56..3bb4ed0 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
index d7eee84..1171dcb 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
index 899e577..03c26f0 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
index aaa6826..f601b3b 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
index e15fc63..dc5233b 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
index cc82a54..2afb586 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
index b756e79..d7416c0 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
index 89bf5b4..47587d2 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
index 50e4940..b258503 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
index 0b77905..703e502 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
index 2e21a6f..966511e 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
index 1a346c9..b6cd6a28 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
index d0c2151..33eb011 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
index fab8dc1..8d55f44 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..c6079cd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..230d649
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
index 7bfdd34..2d4f2300 100644
--- a/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
index 13f76de..bd707b0 100644
--- a/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
index a1b5ed2..922cff7 100644
--- a/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
index 7cfb33d..0f58325 100644
--- a/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index 8a67108..432436f 100644
--- a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index f84557f..b18aed6 100644
--- a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
index 103a2c3..5cb3d60 100644
--- a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
index 4e76add..91528b4 100644
--- a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
index d8b02e0..37e1cdc 100644
--- a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
index 807f2c1..2990407 100644
--- a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
index bdcfc74..94ab960 100644
--- a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
index 302b4e2..b795052 100644
--- a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
index 8987d993d..c2ee05f 100644
--- a/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
index 92419c4..7faf667 100644
--- a/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_cab_done_holo_dark.xml b/core/res/res/drawable/btn_cab_done_holo_dark.xml
index 14f5777..f865ddd 100644
--- a/core/res/res/drawable/btn_cab_done_holo_dark.xml
+++ b/core/res/res/drawable/btn_cab_done_holo_dark.xml
@@ -17,7 +17,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true">
<item android:state_pressed="true"
- android:drawable="@drawable/btn_cab_done_pressed_holo_dark" />
+ android:drawable="@drawable/list_pressed_holo_dark" />
<item android:state_focused="true" android:state_enabled="true"
android:drawable="@drawable/btn_cab_done_focused_holo_dark" />
<item android:state_enabled="true"
diff --git a/core/res/res/drawable/btn_cab_done_holo_light.xml b/core/res/res/drawable/btn_cab_done_holo_light.xml
index a9a634f..6d85fc4 100644
--- a/core/res/res/drawable/btn_cab_done_holo_light.xml
+++ b/core/res/res/drawable/btn_cab_done_holo_light.xml
@@ -17,7 +17,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true">
<item android:state_pressed="true"
- android:drawable="@drawable/btn_cab_done_pressed_holo_light" />
+ android:drawable="@drawable/list_pressed_holo_light" />
<item android:state_focused="true" android:state_enabled="true"
android:drawable="@drawable/btn_cab_done_focused_holo_light" />
<item android:state_enabled="true"
diff --git a/core/res/res/drawable/list_selector_background_transition_holo_dark.xml b/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
index 7c68426..288c778 100644
--- a/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
+++ b/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
@@ -16,5 +16,5 @@
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:drawable/list_pressed_holo_dark" />
- <item android:drawable="@android:drawable/list_longpressed_holo" />
+ <item android:drawable="@android:drawable/list_longpressed_holo_dark" />
</transition>
diff --git a/core/res/res/drawable/list_selector_background_transition_holo_light.xml b/core/res/res/drawable/list_selector_background_transition_holo_light.xml
index fc08a84..b729e1f 100644
--- a/core/res/res/drawable/list_selector_background_transition_holo_light.xml
+++ b/core/res/res/drawable/list_selector_background_transition_holo_light.xml
@@ -16,5 +16,5 @@
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:drawable/list_pressed_holo_light" />
- <item android:drawable="@android:drawable/list_longpressed_holo" />
+ <item android:drawable="@android:drawable/list_longpressed_holo_light" />
</transition>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 80810d5..b20f5ba 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1821,7 +1821,9 @@
<attr name="value" />
</declare-styleable>
- <attr name="keyset" />
+ <!-- Groups signing keys into a {@code KeySet} for easier reference in
+ other APIs. However, currently no APIs use this. -->
+ <attr name="keySet" />
<declare-styleable name="PublicKey">
<attr name="value" />
</declare-styleable>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c5d4810..ef7f2b7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2058,7 +2058,7 @@
=============================================================== -->
<eat-comment />
- <public type="attr" name="keyset" />
+ <public type="attr" name="keySet" />
<public type="attr" name="targetId" />
<public type="attr" name="fromScene" />
<public type="attr" name="toScene" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 98368a1..56b8ca4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1433,6 +1433,11 @@
<string name="permdesc_captureSecureVideoOutput">Allows the app to capture and redirect secure video output.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_mediaContentControl">control media playback and metadata access</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_mediaContentControl">Allows the app to control media playback and access the media information (title, author...).</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_modifyAudioSettings">change your audio settings</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_modifyAudioSettings">Allows the app to modify global audio settings such as volume and which speaker is used for output.</string>
@@ -1898,6 +1903,11 @@
<string name="permdesc_use_sip">Allows the app to use the SIP service to make/receive Internet calls.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bind_call_service">interact with in-call screen</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bind_call_service">Allows the app to control when and how the user sees the in-call screen.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readNetworkUsageHistory">read historical network usage</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_readNetworkUsageHistory">Allows the app to read historical network usage for specific networks and apps.</string>
@@ -4296,19 +4306,111 @@
<!-- ISO (European standard) C10 media (paper) size: 1.10" x 1.57" -->
<string name="mediaSize_iso_c10">ISO C10</string>
- <!-- North America Letter media (paper) size: 8.5" × 11" -->
+ <!-- North America Letter media (paper) size: 8.5" × 11" (279mm x 216mm) -->
<string name="mediaSize_na_letter">Letter</string>
- <!-- North America Government Letter media (paper) size: 8.0" × 10.5" -->
+ <!-- North America Government Letter media (paper) size: 8.0" × 10.5" (203mm x 267mm) -->
<string name="mediaSize_na_gvrnmt_letter">Government Letter</string>
- <!-- North America Legal media (paper) size: 8.5" × 14" -->
+ <!-- North America Legal media (paper) size: 8.5" × 14" (216mm x 356mm) -->
<string name="mediaSize_na_legal">Legal</string>
- <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" -->
+ <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" (203mm × 127mm) -->
<string name="mediaSize_na_junior_legal">Junior Legal</string>
- <!-- North America Ledger media (paper) size: 17" × 11" -->
+ <!-- North America Ledger media (paper) size: 17" × 11" (432mm × 279mm) -->
<string name="mediaSize_na_ledger">Ledger</string>
- <!-- North America Tabloid media (paper) size: 11" × 17" -->
+ <!-- North America Tabloid media (paper) size: 11" × 17" (279mm × 432mm) -->
<string name="mediaSize_na_tabloid">Tabloid</string>
+ <!-- North America Index Card 3x5 media (paper) size: 3" x 5" (76mm x 127mm) -->
+ <string name="mediaSize_na_index_3x5">Index Card 3x5</string>
+ <!-- North America Index Card 4x6 media (paper) size: 4" x 6" (102mm x 152mm) -->
+ <string name="mediaSize_na_index_4x6">Index Card 4x6</string>
+ <!-- North America Index Card 5x8 media (paper) size: 5" x 8" (127mm x 203mm) -->
+ <string name="mediaSize_na_index_5x8">Index Card 5x8</string>
+ <!-- North America Monarch media (paper) size: 7.25" x 10.5" (184mm x 267mm) -->
+ <string name="mediaSize_na_monarch">Monarch</string>
+ <!-- North America Quarto media (paper) size: 8" x 10" (203mm x 254mm) -->
+ <string name="mediaSize_na_quarto">Quarto</string>
+ <!-- North America Foolscap media (paper) size: 8" x 13" (203mm x 330mm) -->
+ <string name="mediaSize_na_foolscap">Foolscap</string>
+
+ <!-- Chinese Roc 8k media (paper) size: 270mm x 390mm (10.629" x 15.3543") -->
+ <string name="mediaSize_chinese_roc_8k">ROC 8K</string>
+ <!-- Chinese Roc 16k media (paper) size: 195mm x 270mm (7.677" x 10.629") -->
+ <string name="mediaSize_chinese_roc_16k">ROC 16K</string>
+
+ <!-- Chinese PRC 1 media (paper) size: 102mm x 165mm (4.015" x 6.496") -->
+ <string name="mediaSize_chinese_prc_1">PRC 1</string>
+ <!-- Chinese PRC 2 media (paper) size: 102mm x 176mm (4.015" x 6.929") -->
+ <string name="mediaSize_chinese_prc_2">PRC 2</string>
+ <!-- Chinese PRC 3 media (paper) size: 125mm x 176mm (4.921" x 6.929") -->
+ <string name="mediaSize_chinese_prc_3">PRC 3</string>
+ <!-- Chinese PRC 4 media (paper) size: 110mm x 208mm (4.330" x 8.189") -->
+ <string name="mediaSize_chinese_prc_4">PRC 4</string>
+ <!-- Chinese PRC 5 media (paper) size: 110mm x 220mm (4.330" x 8.661") -->
+ <string name="mediaSize_chinese_prc_5">PRC 5</string>
+ <!-- Chinese PRC 6 media (paper) size: 120mm x 320mm (4.724" x 12.599") -->
+ <string name="mediaSize_chinese_prc_6">PRC 6</string>
+ <!-- Chinese PRC 7 media (paper) size: 160mm x 230mm (6.299" x 9.055") -->
+ <string name="mediaSize_chinese_prc_7">PRC 7</string>
+ <!-- Chinese PRC 8 media (paper) size: 120mm x 309mm (4.724" x 12.165") -->
+ <string name="mediaSize_chinese_prc_8">PRC 8</string>
+ <!-- Chinese PRC 9 media (paper) size: 229mm x 324mm (9.016" x 12.756") -->
+ <string name="mediaSize_chinese_prc_9">PRC 9</string>
+ <!-- Chinese PRC 10 media (paper) size: 324mm x 458mm (12.756" x 18.032") -->
+ <string name="mediaSize_chinese_prc_10">PRC 10</string>
+
+ <!-- Chinese RPC 16K media (paper) size: 146mm x 215mm (5.749" x 8.465") -->
+ <string name="mediaSize_chinese_prc_16k">PRC 16K</string>
+ <!-- Chinese Pa Kai media (paper) size: 146mm x 215mm (5.749" x 8.465") -->
+ <string name="mediaSize_chinese_om_pa_kai">Pa Kai</string>
+ <!-- Chinese Dai Pa Kai media (paper) size: 275mm x 395mm (10.827" x 15.551") -->
+ <string name="mediaSize_chinese_om_dai_pa_kai">Dai Pa Kai</string>
+ <!-- Chinese Jurro Ku Kai media (paper) size: 275mm x 395mm (10.827" x 15.551") -->
+ <string name="mediaSize_chinese_om_jurro_ku_kai">Jurro Ku Kai</string>
+
+ <!-- Japanese JIS B10 media (paper) size: 32mm x 45mm (1.259" x 1.772") -->
+ <string name="mediaSize_japanese_jis_b10">JIS B10</string>
+ <!-- Japanese JIS B9 media (paper) size: 45mm x 64mm (1.772" x 2.52") -->
+ <string name="mediaSize_japanese_jis_b9">JIS B9</string>
+ <!-- Japanese JIS B8 media (paper) size: 64mm x 91mm (2.52" x 3.583") -->
+ <string name="mediaSize_japanese_jis_b8">JIS B8</string>
+ <!-- Japanese JIS B7 media (paper) size: 91mm x 128mm (3.583" x 5.049") -->
+ <string name="mediaSize_japanese_jis_b7">JIS B7</string>
+ <!-- Japanese JIS B6 media (paper) size: 128mm x 182mm (5.049" x 7.165") -->
+ <string name="mediaSize_japanese_jis_b6">JIS B6</string>
+ <!-- Japanese JIS B5 media (paper) size: 182mm x 257mm (7.165" x 10.118") -->
+ <string name="mediaSize_japanese_jis_b5">JIS B5</string>
+ <!-- Japanese JIS B4 media (paper) size: 257mm x 364mm (10.118" x 14.331") -->
+ <string name="mediaSize_japanese_jis_b4">JIS B4</string>
+ <!-- Japanese JIS B3 media (paper) size: 364mm x 515mm (14.331" x 20.276") -->
+ <string name="mediaSize_japanese_jis_b3">JIS B3</string>
+ <!-- Japanese JIS B2 media (paper) size: 515mm x 728mm (20.276" x 28.661") -->
+ <string name="mediaSize_japanese_jis_b2">JIS B2</string>
+ <!-- Japanese JIS B1 media (paper) size: 728mm x 1030mm (28.661" x 40.551") -->
+ <string name="mediaSize_japanese_jis_b1">JIS B1</string>
+ <!-- Japanese JIS B0 media (paper) size: 1030mm x 1456mm (40.551" x 57.323") -->
+ <string name="mediaSize_japanese_jis_b0">JIS B0</string>
+
+ <!-- Japanese JIS Exec media (paper) size: 216mm x 330mm (8.504" x 12.992") -->
+ <string name="mediaSize_japanese_jis_exec">JIS Exec</string>
+
+ <!-- Japanese Chou4 media (paper) size: 90mm x 205mm (3.543" x 8.071") -->
+ <string name="mediaSize_japanese_chou4">Chou4</string>
+ <!-- Japanese Chou3 media (paper) size: 120mm x 235mm (4.724" x 9.252") -->
+ <string name="mediaSize_japanese_chou3">Chou3</string>
+ <!-- Japanese Chou2 media (paper) size: 111.1mm x 146mm (4.374" x 5.748") -->
+ <string name="mediaSize_japanese_chou2">Chou2</string>
+
+ <!-- Japanese Hagaki media (paper) size: 100mm x 148mm (3.937" x 5.827") -->
+ <string name="mediaSize_japanese_hagaki">Hagaki </string>
+ <!-- Japanese Oufuku media (paper) size: 148mm x 200mm (5.827" x 7.874") -->
+ <string name="mediaSize_japanese_oufuku">Oufuku </string>
+ <!-- Japanese Kahu media (paper) size: 240mm x 322.1mm (9.449" x 12.681") -->
+ <string name="mediaSize_japanese_kahu">Kahu</string>
+ <!-- Japanese Kaku2 media (paper) size: 240mm x 332mm (9.449" x 13.071") -->
+ <string name="mediaSize_japanese_kaku2">Kaku2</string>
+ <!-- Japanese You4 media (paper) size: 105mm x 235mm (4.134" x 9.252") -->
+ <string name="mediaSize_japanese_you4">You4</string>
+
<!-- Write fail reason: printing was cancelled.[CHAR LIMIT=none] -->
<string name="write_fail_reason_cancelled">Cancelled</string>
<!-- Write fail reason: couldn't write the printed content. [CHAR LIMIT=none] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9cb0a37..e82c0e1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -878,6 +878,48 @@
<java-symbol type="string" name="mediaSize_na_junior_legal" />
<java-symbol type="string" name="mediaSize_na_ledger" />
<java-symbol type="string" name="mediaSize_na_tabloid" />
+ <java-symbol type="string" name="mediaSize_na_index_3x5" />
+ <java-symbol type="string" name="mediaSize_na_index_4x6" />
+ <java-symbol type="string" name="mediaSize_na_index_5x8" />
+ <java-symbol type="string" name="mediaSize_na_monarch" />
+ <java-symbol type="string" name="mediaSize_na_quarto" />
+ <java-symbol type="string" name="mediaSize_na_foolscap" />
+ <java-symbol type="string" name="mediaSize_chinese_roc_8k" />
+ <java-symbol type="string" name="mediaSize_chinese_roc_16k" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_1" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_2" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_3" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_4" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_5" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_6" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_7" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_8" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_9" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_10" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_16k" />
+ <java-symbol type="string" name="mediaSize_chinese_om_pa_kai" />
+ <java-symbol type="string" name="mediaSize_chinese_om_dai_pa_kai" />
+ <java-symbol type="string" name="mediaSize_chinese_om_jurro_ku_kai" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b10" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b9" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b8" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b7" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b6" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b5" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b4" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b3" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b2" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b1" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b0" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_exec" />
+ <java-symbol type="string" name="mediaSize_japanese_chou4" />
+ <java-symbol type="string" name="mediaSize_japanese_chou3" />
+ <java-symbol type="string" name="mediaSize_japanese_chou2" />
+ <java-symbol type="string" name="mediaSize_japanese_hagaki" />
+ <java-symbol type="string" name="mediaSize_japanese_oufuku" />
+ <java-symbol type="string" name="mediaSize_japanese_kahu" />
+ <java-symbol type="string" name="mediaSize_japanese_kaku2" />
+ <java-symbol type="string" name="mediaSize_japanese_you4" />
<java-symbol type="string" name="reason_unknown" />
<java-symbol type="string" name="restr_pin_enter_admin_pin" />
<java-symbol type="string" name="restr_pin_enter_pin" />
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 23606a1..c8ace44 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -569,10 +569,7 @@
final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
bm = nativeDecodeAsset(asset, outPadding, opts);
} else {
- byte [] tempStorage = null;
- if (opts != null) tempStorage = opts.inTempStorage;
- if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
- bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
+ bm = decodeStreamInternal(is, outPadding, opts);
}
if (bm == null && opts != null && opts.inBitmap != null) {
@@ -588,6 +585,18 @@
}
/**
+ * Private helper function for decoding an InputStream natively. Buffers the input enough to
+ * do a rewind as needed, and supplies temporary storage if necessary. is MUST NOT be null.
+ */
+ private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {
+ // ASSERT(is != null);
+ byte [] tempStorage = null;
+ if (opts != null) tempStorage = opts.inTempStorage;
+ if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
+ return nativeDecodeStream(is, tempStorage, outPadding, opts);
+ }
+
+ /**
* Decode an input stream into a bitmap. If the input stream is null, or
* cannot be used to decode a bitmap, the function returns null.
* The stream's position will be where ever it was after the encoded data
@@ -624,13 +633,8 @@
bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
} else {
FileInputStream fis = new FileInputStream(fd);
- // FIXME: If nativeDecodeStream grabbed the pointer to tempStorage
- // from Options, this code would not need to be duplicated.
- byte [] tempStorage = null;
- if (opts != null) tempStorage = opts.inTempStorage;
- if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
try {
- bm = nativeDecodeStream(fis, tempStorage, outPadding, opts);
+ bm = decodeStreamInternal(fis, outPadding, opts);
} finally {
try {
fis.close();
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 4a33453..9419faf 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -16,12 +16,13 @@
package android.graphics;
+import android.content.res.AssetManager;
import java.io.InputStream;
import java.io.FileInputStream;
public class Movie {
private final int mNativeMovie;
-
+
private Movie(int nativeMovie) {
if (nativeMovie == 0) {
throw new RuntimeException("native movie creation failed");
@@ -42,7 +43,20 @@
draw(canvas, x, y, null);
}
- public static native Movie decodeStream(InputStream is);
+ public static Movie decodeStream(InputStream is) {
+ if (is == null) {
+ return null;
+ }
+ if (is instanceof AssetManager.AssetInputStream) {
+ final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+ return nativeDecodeAsset(asset);
+ }
+
+ return nativeDecodeStream(is);
+ }
+
+ private static native Movie nativeDecodeAsset(int asset);
+ private static native Movie nativeDecodeStream(InputStream is);
public static native Movie decodeByteArray(byte[] data, int offset,
int length);
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index c0b77c7..7eb7028 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -275,6 +275,11 @@
DisplayListLogBuffer& buffer = DisplayListLogBuffer::getInstance();
buffer.writeCommand(0, "multiDraw");
buffer.writeCommand(1, op->name());
+
+#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
+ renderer.eventMark("multiDraw");
+ renderer.eventMark(op->name());
+#endif
status_t status = op->multiDraw(renderer, dirty, mOps, mBounds);
#if DEBUG_MERGE_BEHAVIOR
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index a17942e..b052461 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -813,12 +813,15 @@
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
- deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
+ deferInfo.mergeId = getAtlasEntry() ?
+ (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
+ // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
// Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
// MergingDrawBatch::canMergeWith()
// TODO: support clipped bitmaps by handling them in SET_TEXTURE
- deferInfo.mergeable = state.mMatrix.isSimple() && !state.mClipSideFlags &&
+ deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() &&
+ !state.mClipSideFlags &&
OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
(mBitmap->getConfig() != SkBitmap::kA8_Config);
}
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 65e7eae..1948778 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -110,6 +110,10 @@
mType |= kTypeRectToRect;
}
}
+
+ if (m00 > 0.0f && m11 > 0.0f) {
+ mType |= kTypePositiveScale;
+ }
}
return mType;
}
@@ -122,6 +126,10 @@
return getType() & kTypeRectToRect;
}
+bool Matrix4::positiveScale() const {
+ return getType() & kTypePositiveScale;
+}
+
bool Matrix4::changesBounds() const {
return getType() & (kTypeScale | kTypeAffine | kTypePerspective);
}
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 5116203..e2c5b20 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -64,7 +64,8 @@
kTypeAffine = 0x4,
kTypePerspective = 0x8,
kTypeRectToRect = 0x10,
- kTypeUnknown = 0x20,
+ kTypePositiveScale = 0x20,
+ kTypeUnknown = 0x40,
};
static const int sGeometryMask = 0xf;
@@ -183,6 +184,7 @@
bool isIdentity() const;
bool isPerspective() const;
bool rectToRect() const;
+ bool positiveScale() const;
bool changesBounds() const;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2066f69..89a82fd 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1628,14 +1628,7 @@
Rect r(left, top, right, bottom);
currentTransform().mapRect(r);
-
- if (snapOut) {
- // snapOut is generally used to account for 1 pixel ramp (in window coordinates)
- // outside of the provided rect boundaries in tessellated AA geometry
- r.snapOutToPixelBoundaries();
- } else {
- r.snapToPixelBoundaries();
- }
+ r.snapGeometryToPixelBoundaries(snapOut);
Rect clipRect(*mSnapshot->clipRect);
clipRect.snapToPixelBoundaries();
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 9e4670e..7814a01 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -20,6 +20,7 @@
#include <utils/Trace.h>
#include "Program.h"
+#include "Vertex.h"
namespace android {
namespace uirenderer {
@@ -172,7 +173,7 @@
// up and to the left.
// This offset value is based on an assumption that some hardware may use as
// little as 12.4 precision, so we offset by slightly more than 1/16.
- p.translate(.065, .065);
+ p.translate(Vertex::gGeometryFudgeFactor, Vertex::gGeometryFudgeFactor);
glUniformMatrix4fv(projection, 1, GL_FALSE, &p.data[0]);
}
mProjection = projectionMatrix;
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 7605307..dabd8d4 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -21,6 +21,8 @@
#include <utils/Log.h>
+#include "Vertex.h"
+
namespace android {
namespace uirenderer {
@@ -171,17 +173,37 @@
}
/**
- * Similar to snapToPixelBoundaries, but used for AA geometry with a ramp perimeter.
+ * Similar to snapToPixelBoundaries, but estimates bounds conservatively to handle GL rounding
+ * errors.
*
- * We inset the data by a fudge factor of slightly over 1/16 (similar to when drawing non-AA
- * lines) before rounding out so that insignificant amounts of ramp geometry (esp. from rounding
- * errors) are ignored.
+ * This function should be used whenever estimating the damage rect of geometry already mapped
+ * into layer space.
*/
- void snapOutToPixelBoundaries() {
- left = floorf(left + 0.065f);
- top = floorf(top + 0.065f);
- right = ceilf(right - 0.065f);
- bottom = ceilf(bottom - 0.065f);
+ void snapGeometryToPixelBoundaries(bool snapOut) {
+ if (snapOut) {
+ /* For AA geometry with a ramp perimeter, don't snap by rounding - AA geometry will have
+ * a 0.5 pixel perimeter not accounted for in its bounds. Instead, snap by
+ * conservatively rounding out the bounds with floor/ceil.
+ *
+ * In order to avoid changing integer bounds with floor/ceil due to rounding errors
+ * inset the bounds first by the fudge factor. Very small fraction-of-a-pixel errors
+ * from this inset will only incur similarly small errors in output, due to transparency
+ * in extreme outside of the geometry.
+ */
+ left = floorf(left + Vertex::gGeometryFudgeFactor);
+ top = floorf(top + Vertex::gGeometryFudgeFactor);
+ right = ceilf(right - Vertex::gGeometryFudgeFactor);
+ bottom = ceilf(bottom - Vertex::gGeometryFudgeFactor);
+ } else {
+ /* For other geometry, we do the regular rounding in order to snap, but also outset the
+ * bounds by a fudge factor. This ensures that ambiguous geometry (e.g. a non-AA Rect
+ * with top left at (0.5, 0.5)) will err on the side of a larger damage rect.
+ */
+ left = floorf(left + 0.5f - Vertex::gGeometryFudgeFactor);
+ top = floorf(top + 0.5f - Vertex::gGeometryFudgeFactor);
+ right = floorf(right + 0.5f + Vertex::gGeometryFudgeFactor);
+ bottom = floorf(bottom + 0.5f + Vertex::gGeometryFudgeFactor);
+ }
}
void snapToPixelBoundaries() {
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index c06762f..790d4fc 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -26,6 +26,15 @@
* Simple structure to describe a vertex with a position and a texture.
*/
struct Vertex {
+ /**
+ * Fudge-factor used to disambiguate geometry pixel positioning.
+ *
+ * Used to offset lines and points to avoid ambiguous intersection with pixel centers (see
+ * Program::set()), and used to make geometry damage rect calculation conservative (see
+ * Rect::snapGeometryToPixelBoundaries())
+ */
+ static const float gGeometryFudgeFactor = 0.0656f;
+
float position[2];
static inline void set(Vertex* vertex, float x, float y) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 845baaf..a4009cf 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -323,6 +323,12 @@
public static final int FLAG_FIXED_VOLUME = 1 << 5;
/**
+ * Indicates the volume set/adjust call is for Bluetooth absolute volume
+ * @hide
+ */
+ public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
+
+ /**
* Ringer mode that will be silent and will not vibrate. (This overrides the
* vibrate setting.)
*
@@ -438,6 +444,19 @@
/**
* @hide
+ * @param KeyEvent
+ */
+ protected void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+ IAudioService service = getService();
+ try {
+ service.dispatchMediaKeyEvent(keyEvent);
+ } catch (RemoteException e) {
+ Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
+ }
+ }
+
+ /**
+ * @hide
*/
public void preDispatchKeyEvent(KeyEvent event, int stream) {
/*
@@ -2229,6 +2248,49 @@
/**
* @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param rctlr
+ * @return true if the {@link RemoteController} was successfully registered, false if an
+ * error occurred, due to an internal system error, or insufficient permissions.
+ */
+ public boolean registerRemoteController(RemoteController rctlr) {
+ if (rctlr == null) {
+ return false;
+ }
+ IAudioService service = getService();
+ try {
+ boolean reg = service.registerRemoteControlDisplay(rctlr.getRcDisplay(),
+ // passing a negative value for art work width and height
+ // as they are still unknown at this stage
+ /*w*/-1, /*h*/ -1);
+ rctlr.setIsRegistered(reg);
+ return reg;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
+ return false;
+ }
+ }
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param rctlr
+ */
+ public void unregisterRemoteController(RemoteController rctlr) {
+ if (rctlr == null) {
+ return;
+ }
+ IAudioService service = getService();
+ try {
+ service.unregisterRemoteControlDisplay(rctlr.getRcDisplay());
+ rctlr.setIsRegistered(false);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e);
+ }
+ }
+
+ /**
+ * @hide
* Registers a remote control display that will be sent information by remote control clients.
* Use this method if your IRemoteControlDisplay is not going to display artwork, otherwise
* use {@link #registerRemoteControlDisplay(IRemoteControlDisplay, int, int)} to pass the
@@ -2257,8 +2319,6 @@
}
IAudioService service = getService();
try {
- // passing a negative value for art work width and height as they are unknown at
- // this stage
service.registerRemoteControlDisplay(rcd, w, h);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
@@ -2351,13 +2411,15 @@
/**
* @hide
- * Notify the user of a RemoteControlClient that it should update its metadata
+ * Notify the user of a RemoteControlClient that it should update its metadata with the
+ * new value for the given key.
* @param generationId the RemoteControlClient generation counter for which this request is
* issued. Requests for an older generation than current one will be ignored.
* @param key the metadata key for which a new value exists
* @param value the new metadata value
*/
- public void updateRemoteControlClientMetadata(int generationId, int key, long value) {
+ public void updateRemoteControlClientMetadata(int generationId, int key,
+ Rating value) {
IAudioService service = getService();
try {
service.updateRemoteControlClientMetadata(generationId, key, value);
@@ -2397,20 +2459,6 @@
}
}
- /**
- * @hide
- * Notifies AudioService of the volume set on the A2DP device as a callback, so AudioService
- * is able to update the UI.
- */
- public void avrcpUpdateVolume(int oldVolume, int volume) {
- IAudioService service = getService();
- try {
- service.avrcpUpdateVolume(oldVolume, volume);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in avrcpUpdateVolume", e);
- }
- }
-
/**
* {@hide}
*/
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index b72551a..3425c91 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -843,6 +843,13 @@
boolean adjustVolume = true;
int step;
+ // skip a2dp absolute volume control request when the device
+ // is not an a2dp device
+ if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+ (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+ return;
+ }
+
if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
callingPackage) != AppOpsManager.MODE_ALLOWED) {
return;
@@ -892,15 +899,18 @@
int oldIndex = mStreamStates[streamType].getIndex(device);
if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
+
// Check if volume update should be send to AVRCP
- synchronized (mA2dpAvrcpLock) {
- if (mA2dp != null && mAvrcpAbsVolSupported) {
- mA2dp.adjustAvrcpAbsoluteVolume(direction);
- return;
- // No need to send volume update, because we will update the volume with a
- // callback from Avrcp.
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+ (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+ (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+ synchronized (mA2dpAvrcpLock) {
+ if (mA2dp != null && mAvrcpAbsVolSupported) {
+ mA2dp.adjustAvrcpAbsoluteVolume(direction);
+ }
}
}
+
if ((direction == AudioManager.ADJUST_RAISE) &&
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
@@ -985,6 +995,13 @@
final int device = getDeviceForStream(streamType);
int oldIndex;
+ // skip a2dp absolute volume control request when the device
+ // is not an a2dp device
+ if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+ (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+ return;
+ }
+
if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
callingPackage) != AppOpsManager.MODE_ALLOWED) {
return;
@@ -998,12 +1015,13 @@
index = rescaleIndex(index * 10, streamType, streamTypeAlias);
- synchronized (mA2dpAvrcpLock) {
- if (mA2dp != null && mAvrcpAbsVolSupported) {
- mA2dp.setAvrcpAbsoluteVolume(index);
- return;
- // No need to send volume update, because we will update the volume with a
- // callback from Avrcp.
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+ (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+ (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+ synchronized (mA2dpAvrcpLock) {
+ if (mA2dp != null && mAvrcpAbsVolSupported) {
+ mA2dp.setAvrcpAbsoluteVolume(index);
+ }
}
}
@@ -2835,7 +2853,12 @@
int index;
if (isMuted()) {
index = 0;
- } else {
+ } else if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC &&
+ (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+ mAvrcpAbsVolSupported) {
+ index = (mIndexMax + 5)/10;
+ }
+ else {
index = (getIndex(device) + 5)/10;
}
AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
@@ -3650,6 +3673,9 @@
private void makeA2dpDeviceAvailable(String address) {
// enable A2DP before notifying A2DP connection to avoid unecessary processing in
// audio policy manager
+ VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+ sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
setBluetoothA2dpOnInt(true);
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_AVAILABLE,
@@ -3666,6 +3692,9 @@
// must be called synchronized on mConnectedDevices
private void makeA2dpDeviceUnavailableNow(String address) {
+ synchronized (mA2dpAvrcpLock) {
+ mAvrcpAbsVolSupported = false;
+ }
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
address);
@@ -3706,19 +3735,6 @@
address = "";
}
- // Disable absolute volume, if device is disconnected
- synchronized (mA2dpAvrcpLock) {
- if (state == BluetoothProfile.STATE_DISCONNECTED && mAvrcpAbsVolSupported) {
- mAvrcpAbsVolSupported = false;
- sendMsg(mAudioHandler,
- MSG_SET_DEVICE_VOLUME,
- SENDMSG_QUEUE,
- getDeviceForStream(AudioSystem.STREAM_MUSIC),
- 0,
- mStreamStates[AudioSystem.STREAM_MUSIC],
- 0);
- }
- }
synchronized (mConnectedDevices) {
boolean isConnected =
(mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
@@ -3773,27 +3789,12 @@
// address is not used for now, but may be used when multiple a2dp devices are supported
synchronized (mA2dpAvrcpLock) {
mAvrcpAbsVolSupported = support;
- if (support) {
- VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
- int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
- streamState.setIndex(streamState.getMaxIndex(), device);
- sendMsg(mAudioHandler,
- MSG_SET_DEVICE_VOLUME,
- SENDMSG_QUEUE,
- device,
- 0,
- streamState,
- 0);
- }
+ VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+ sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
}
}
- public void avrcpUpdateVolume(int oldVolume, int volume) {
- mStreamStates[AudioSystem.STREAM_MUSIC].
- setIndex(volume, getDeviceForStream(AudioSystem.STREAM_MUSIC));
- sendVolumeUpdate(AudioSystem.STREAM_MUSIC, oldVolume, volume, AudioManager.FLAG_SHOW_UI);
- }
-
private boolean handleDeviceConnection(boolean connected, int device, String params) {
synchronized (mConnectedDevices) {
boolean isConnected = (mConnectedDevices.containsKey(device) &&
@@ -4142,8 +4143,17 @@
//==========================================================================================
// RemoteControlDisplay / RemoteControlClient / Remote info
//==========================================================================================
- public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
- mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
+ public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
+ if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MEDIA_CONTENT_CONTROL)) {
+ mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
+ return true;
+ } else {
+ Log.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
+ ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
+ " to register IRemoteControlDisplay");
+ return false;
+ }
}
public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
@@ -4189,7 +4199,7 @@
mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs);
}
- public void updateRemoteControlClientMetadata(int generationId, int key, long value) {
+ public void updateRemoteControlClientMetadata(int generationId, int key, Rating value) {
mMediaFocusControl.updateRemoteControlClientMetadata(generationId, key, value);
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fe060f8..e3b87dd 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -26,6 +26,7 @@
import android.media.IRemoteControlDisplay;
import android.media.IRemoteVolumeObserver;
import android.media.IRingtonePlayer;
+import android.media.Rating;
import android.net.Uri;
import android.view.KeyEvent;
@@ -100,8 +101,6 @@
oneway void avrcpSupportsAbsoluteVolume(String address, boolean support);
- oneway void avrcpUpdateVolume(int oldVolume, int volume);
-
void setSpeakerphoneOn(boolean on);
boolean isSpeakerphoneOn();
@@ -142,7 +141,7 @@
* @param h the maximum height of the expected bitmap. Negative or zero values indicate this
* display doesn't need to receive artwork.
*/
- oneway void registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
+ boolean registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
/**
* Unregister an IRemoteControlDisplay.
* No effect if the IRemoteControlDisplay hasn't been successfully registered.
@@ -180,13 +179,14 @@
*/
void setRemoteControlClientPlaybackPosition(int generationId, long timeMs);
/**
- * Notify the user of a RemoteControlClient that it should update its metadata
+ * Notify the user of a RemoteControlClient that it should update its metadata with the
+ * new value for the given key.
* @param generationId the RemoteControlClient generation counter for which this request is
* issued. Requests for an older generation than current one will be ignored.
* @param key the metadata key for which a new value exists
* @param value the new metadata value
*/
- void updateRemoteControlClientMetadata(int generationId, int key, long value);
+ void updateRemoteControlClientMetadata(int generationId, int key, in Rating value);
/**
* Do not use directly, use instead
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
index dd729b4..48079f2 100644
--- a/media/java/android/media/IRemoteControlClient.aidl
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -17,6 +17,7 @@
import android.graphics.Bitmap;
import android.media.IRemoteControlDisplay;
+import android.media.Rating;
/**
* @hide
@@ -49,5 +50,5 @@
void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync);
void seekTo(int clientGeneration, long timeMs);
- void updateMetadata(int clientGeneration, int key, long value);
+ void updateMetadata(int clientGeneration, int key, in Rating value);
}
\ No newline at end of file
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index aee8362..1bd32c4 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -20,6 +20,7 @@
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
+import android.os.Message;
import android.view.Surface;
import java.lang.ref.WeakReference;
@@ -82,7 +83,8 @@
* @param format
* The format of the Image that this reader will produce. This
* must be one of the {@link android.graphics.ImageFormat} or
- * {@link android.graphics.PixelFormat} constants.
+ * {@link android.graphics.PixelFormat} constants. Note that
+ * not all formats is supported, like ImageFormat.NV21.
* @param maxImages
* The maximum number of images the user will want to
* access simultaneously. This should be as small as possible to limit
@@ -115,6 +117,11 @@
"Maximum outstanding image count must be at least 1");
}
+ if (format == ImageFormat.NV21) {
+ throw new IllegalArgumentException(
+ "NV21 format is not supported");
+ }
+
mNumPlanes = getNumPlanesFromFormat();
nativeInit(new WeakReference<ImageReader>(this), width, height, format, maxImages);
@@ -377,17 +384,21 @@
* @throws IllegalArgumentException
* If no handler specified and the calling thread has no looper.
*/
- public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
- mImageListener = listener;
-
- Looper looper;
- mHandler = handler;
- if (listener != null && mHandler == null) {
- if ((looper = Looper.myLooper()) != null) {
- mHandler = new Handler();
+ public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
+ synchronized (mListenerLock) {
+ if (listener != null) {
+ Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
+ if (looper == null) {
+ throw new IllegalArgumentException(
+ "handler is null but the current thread is not a looper");
+ }
+ if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
+ mListenerHandler = new ListenerHandler(looper);
+ }
+ mListener = listener;
} else {
- throw new IllegalArgumentException(
- "Looper doesn't exist in the calling thread");
+ mListener = null;
+ mListenerHandler = null;
}
}
}
@@ -426,6 +437,7 @@
*/
@Override
public void close() {
+ setOnImageAvailableListener(null, null);
nativeClose();
}
@@ -474,6 +486,9 @@
/**
* Called from Native code when an Event happens.
+ *
+ * This may be called from an arbitrary Binder thread, so access to the ImageReader must be
+ * synchronized appropriately.
*/
private static void postEventFromNative(Object selfRef) {
@SuppressWarnings("unchecked")
@@ -483,16 +498,16 @@
return;
}
- if (ir.mHandler != null && ir.mImageListener != null) {
- ir.mHandler.post(new Runnable() {
- @Override
- public void run() {
- ir.mImageListener.onImageAvailable(ir);
- }
- });
+ final Handler handler;
+ synchronized (ir.mListenerLock) {
+ handler = ir.mListenerHandler;
+ }
+ if (handler != null) {
+ handler.sendEmptyMessage(0);
}
}
+
private final int mWidth;
private final int mHeight;
private final int mFormat;
@@ -500,14 +515,35 @@
private final int mNumPlanes;
private final Surface mSurface;
- private Handler mHandler;
- private OnImageAvailableListener mImageListener;
+ private final Object mListenerLock = new Object();
+ private OnImageAvailableListener mListener;
+ private ListenerHandler mListenerHandler;
/**
* This field is used by native code, do not access or modify.
*/
private long mNativeContext;
+ /**
+ * This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
+ */
+ private final class ListenerHandler extends Handler {
+ public ListenerHandler(Looper looper) {
+ super(looper, null, true /*async*/);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ OnImageAvailableListener listener;
+ synchronized (mListenerLock) {
+ listener = mListener;
+ }
+ if (listener != null) {
+ listener.onImageAvailable(ImageReader.this);
+ }
+ }
+ }
+
private class SurfaceImage extends android.media.Image {
public SurfaceImage() {
mIsImageValid = false;
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 1250cbc..5175830 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -20,7 +20,9 @@
import android.media.MediaCodecList;
import android.media.MediaCrypto;
import android.media.MediaFormat;
+import android.os.Bundle;
import android.view.Surface;
+
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Map;
@@ -576,7 +578,7 @@
* Change a video encoder's target bitrate on the fly. The value is an
* Integer object containing the new bitrate in bps.
*/
- public static final String PARAMETER_KEY_VIDEO_BITRATE = "videoBitrate";
+ public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
/**
* Temporarily suspend/resume encoding of input data. While suspended
@@ -598,7 +600,7 @@
/**
* Communicate additional parameter changes to the component instance.
*/
- public final void setParameters(Map<String, Object> params) {
+ public final void setParameters(Bundle params) {
if (params == null) {
return;
}
@@ -607,9 +609,9 @@
Object[] values = new Object[params.size()];
int i = 0;
- for (Map.Entry<String, Object> entry: params.entrySet()) {
- keys[i] = entry.getKey();
- values[i] = entry.getValue();
+ for (final String key: params.keySet()) {
+ keys[i] = key;
+ values[i] = params.get(key);
++i;
}
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index ab686e6..143ddf2 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -138,7 +138,7 @@
private static final int MSG_PROMOTE_RCC = 6;
private static final int MSG_RCC_NEW_PLAYBACK_STATE = 7;
private static final int MSG_RCC_SEEK_REQUEST = 8;
- private static final int MSG_RCC_UPDATE_METADATA_LONG = 9;
+ private static final int MSG_RCC_UPDATE_METADATA = 9;
// sendMsg() flags
/** If the msg is already queued, replace it with this one. */
@@ -206,9 +206,9 @@
msg.arg1 /* generationId */, ((Long)msg.obj).longValue() /* timeMs */);
break;
- case MSG_RCC_UPDATE_METADATA_LONG:
- onUpdateRemoteControlClientMetadataLong(msg.arg1 /*genId*/, msg.arg2 /*key*/,
- ((Long)msg.obj).longValue() /* value */);
+ case MSG_RCC_UPDATE_METADATA:
+ onUpdateRemoteControlClientMetadata(msg.arg1 /*genId*/, msg.arg2 /*key*/,
+ (Rating) msg.obj /* value */);
break;
case MSG_PROMOTE_RCC:
@@ -720,11 +720,7 @@
}
}
- private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
- if (keyEvent == null) {
- return false;
- }
- final int keyCode = keyEvent.getKeyCode();
+ protected static boolean isMediaKeyCode(int keyCode) {
switch (keyCode) {
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_HEADSETHOOK:
@@ -740,11 +736,17 @@
case KeyEvent.KEYCODE_MEDIA_CLOSE:
case KeyEvent.KEYCODE_MEDIA_EJECT:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
- break;
+ return true;
default:
return false;
}
- return true;
+ }
+
+ private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
+ if (keyEvent == null) {
+ return false;
+ }
+ return MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode());
}
/**
@@ -2080,20 +2082,20 @@
}
}
- protected void updateRemoteControlClientMetadata(int genId, int key, long value) {
- sendMsg(mEventHandler, MSG_RCC_UPDATE_METADATA_LONG, SENDMSG_QUEUE,
- genId /* arg1 */, key /* arg2 */, Long.valueOf(value) /* obj */, 0 /* delay */);
+ protected void updateRemoteControlClientMetadata(int genId, int key, Rating value) {
+ sendMsg(mEventHandler, MSG_RCC_UPDATE_METADATA, SENDMSG_QUEUE,
+ genId /* arg1 */, key /* arg2 */, value /* obj */, 0 /* delay */);
}
- private void onUpdateRemoteControlClientMetadataLong(int genId, int key, long value) {
- if(DEBUG_RC) Log.d(TAG, "onUpdateRemoteControlClientMetadataLong(genId=" + genId +
- ", what=" + key + ",val=" + value + ")");
+ private void onUpdateRemoteControlClientMetadata(int genId, int key, Rating value) {
+ if(DEBUG_RC) Log.d(TAG, "onUpdateRemoteControlClientMetadata(genId=" + genId +
+ ", what=" + key + ",rating=" + value + ")");
synchronized(mRCStack) {
synchronized(mCurrentRcLock) {
if ((mCurrentRcClient != null) && (mCurrentRcClientGen == genId)) {
try {
switch (key) {
- case RemoteControlClient.MetadataEditor.LONG_KEY_RATING_BY_USER:
+ case MediaMetadataEditor.RATING_KEY_BY_USER:
mCurrentRcClient.updateMetadata(genId, key, value);
break;
default:
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 16ae43d..0f7906e 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -85,8 +85,8 @@
public static final String KEY_MIME = "mime";
/**
- * A key describing the language of the content.
- * The associated value is a string.
+ * A key describing the language of the content, using either ISO 639-1
+ * or 639-2/T codes. The associated value is a string.
*/
public static final String KEY_LANGUAGE = "language";
@@ -222,26 +222,36 @@
public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
/**
- * A key for boolean AUTOSELECT field. Tracks with AUTOSELECT=true are
- * considered when automatically selecting a track without specific user
- * choice (as defined by HLS).
- * @hide
+ * A key for boolean AUTOSELECT behavior for the track. Tracks with AUTOSELECT=true
+ * are considered when automatically selecting a track without specific user
+ * choice, based on the current locale.
+ * This is currently only used for subtitle tracks, when the user selected
+ * 'Default' for the captioning locale.
+ * The associated value is an integer, where non-0 means TRUE. This is an optional
+ * field; if not specified, AUTOSELECT defaults to TRUE.
*/
- public static final String KEY_AUTOSELECT = "autoselect";
+ public static final String KEY_IS_AUTOSELECT = "is-autoselect";
/**
- * A key for boolean DEFAULT field. The track with DEFAULT=true is selected
- * in the absence of a specific user choice (as defined by HLS).
- * @hide
+ * A key for boolean DEFAULT behavior for the track. The track with DEFAULT=true is
+ * selected in the absence of a specific user choice.
+ * This is currently only used for subtitle tracks, when the user selected
+ * 'Default' for the captioning locale.
+ * The associated value is an integer, where non-0 means TRUE. This is an optional
+ * field; if not specified, DEFAULT is considered to be FALSE.
*/
- public static final String KEY_DEFAULT = "default";
+ public static final String KEY_IS_DEFAULT = "is-default";
+
/**
- * A key for boolean FORCED field for subtitle tracks. True if it is a
- * forced subtitle track.
- * @hide
+ * A key for the FORCED field for subtitle tracks. True if it is a
+ * forced subtitle track. Forced subtitle tracks are essential for the
+ * content and are shown even when the user turns off Captions. They
+ * are used for example to translate foreign/alien dialogs or signs.
+ * The associated value is an integer, where non-0 means TRUE. This is an
+ * optional field; if not specified, FORCED defaults to FALSE.
*/
- public static final String KEY_FORCED = "forced";
+ public static final String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
/* package private */ MediaFormat(Map<String, Object> map) {
mMap = map;
@@ -370,9 +380,10 @@
/**
* Creates a minimal subtitle format.
* @param mime The mime type of the content.
- * @param language The language of the content. Specify "und" if language
- * information is only included in the content (similarly, if there
- * are multiple language tracks in the content.)
+ * @param language The language of the content, using either ISO 639-1 or 639-2/T
+ * codes. Specify null or "und" if language information is only included
+ * in the content. (This will also work if there are multiple language
+ * tracks in the content.)
*/
public static final MediaFormat createSubtitleFormat(
String mime,
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
new file mode 100644
index 0000000..373ba11
--- /dev/null
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2013 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 android.media;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+/**
+ * An abstract class for editing and storing metadata that can be published by
+ * {@link RemoteControlClient}. See the {@link RemoteControlClient#editMetadata(boolean)}
+ * method to instantiate a {@link RemoteControlClient.MetadataEditor} object.
+ */
+public abstract class MediaMetadataEditor {
+
+ private final static String TAG = "MediaMetadataEditor";
+ /**
+ * @hide
+ */
+ protected MediaMetadataEditor() {
+ }
+
+ // Public keys for metadata used by RemoteControlClient and RemoteController.
+ // Note that these keys are defined here, and not in MediaMetadataRetriever
+ // because they are not supported by the MediaMetadataRetriever features.
+ /**
+ * The metadata key for the content artwork / album art.
+ */
+ public final static int BITMAP_KEY_ARTWORK =
+ RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK;
+
+ /**
+ * The metadata key for the content's average rating, not the user's rating.
+ * The value associated with this key is a {@link Rating} instance.
+ * @see #RATING_KEY_BY_USER
+ */
+ public final static int RATING_KEY_BY_OTHERS = 101;
+
+ /**
+ * The metadata key for the content's user rating.
+ * The value associated with this key is a {@link Rating} instance.
+ * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable
+ * receiving user rating values through the
+ * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface.
+ */
+ public final static int RATING_KEY_BY_USER = 0x10000001;
+
+ /**
+ * @hide
+ * Editable key mask
+ */
+ public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF;
+
+
+ /**
+ * Applies all of the metadata changes that have been set since the MediaMetadataEditor instance
+ * was created or since {@link #clear()} was called.
+ */
+ public abstract void apply();
+
+
+ /**
+ * @hide
+ * Mask of editable keys.
+ */
+ protected long mEditableKeys;
+
+ /**
+ * @hide
+ */
+ protected boolean mMetadataChanged = false;
+
+ /**
+ * @hide
+ */
+ protected boolean mApplied = false;
+
+ /**
+ * @hide
+ */
+ protected boolean mArtworkChanged = false;
+
+ /**
+ * @hide
+ */
+ protected Bitmap mEditorArtwork;
+
+ /**
+ * @hide
+ */
+ protected Bundle mEditorMetadata;
+
+
+ /**
+ * Clears all the pending metadata changes set since the MediaMetadataEditor instance was
+ * created or since this method was last called.
+ * Note that clearing the metadata doesn't reset the editable keys
+ * (use {@link #removeEditableKeys()} instead).
+ */
+ public synchronized void clear() {
+ if (mApplied) {
+ Log.e(TAG, "Can't clear a previously applied MediaMetadataEditor");
+ return;
+ }
+ mEditorMetadata.clear();
+ mEditorArtwork = null;
+ }
+
+ /**
+ * Flags the given key as being editable.
+ * This should only be used by metadata publishers, such as {@link RemoteControlClient},
+ * which will declare the metadata field as eligible to be updated, with new values
+ * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface.
+ * @param key the type of metadata that can be edited. The supported key is
+ * {@link #RATING_KEY_BY_USER}.
+ */
+ public synchronized void addEditableKey(int key) {
+ if (mApplied) {
+ Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor");
+ return;
+ }
+ // only one editable key at the moment, so we're not wasting memory on an array
+ // of editable keys to check the validity of the key, just hardcode the supported key.
+ if (key == RATING_KEY_BY_USER) {
+ mEditableKeys |= (KEY_EDITABLE_MASK & key);
+ mMetadataChanged = true;
+ } else {
+ Log.e(TAG, "Metadata key " + key + " cannot be edited");
+ }
+ }
+
+ /**
+ * Causes all metadata fields to be read-only.
+ */
+ public synchronized void removeEditableKeys() {
+ if (mApplied) {
+ Log.e(TAG, "Can't remove all editable keys of a previously applied MetadataEditor");
+ return;
+ }
+ if (mEditableKeys != 0) {
+ mEditableKeys = 0;
+ mMetadataChanged = true;
+ }
+ }
+
+ /**
+ * Retrieves the keys flagged as editable.
+ * @return null if there are no editable keys, or an array containing the keys.
+ */
+ public synchronized int[] getEditableKeys() {
+ // only one editable key supported here
+ if (mEditableKeys == RATING_KEY_BY_USER) {
+ int[] keys = { RATING_KEY_BY_USER };
+ return keys;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Adds textual information.
+ * Note that none of the information added after {@link #apply()} has been called,
+ * will be available to consumers of metadata stored by the MediaMetadataEditor.
+ * @param key The identifier of a the metadata field to set. Valid values are
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
+ * @param value The text for the given key, or {@code null} to signify there is no valid
+ * information for the field.
+ * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+ * calls together.
+ */
+ public synchronized MediaMetadataEditor putString(int key, String value)
+ throws IllegalArgumentException {
+ if (mApplied) {
+ Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+ return this;
+ }
+ if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
+ throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+ }
+ mEditorMetadata.putString(String.valueOf(key), value);
+ mMetadataChanged = true;
+ return this;
+ }
+
+ /**
+ * Adds numerical information.
+ * Note that none of the information added after {@link #apply()} has been called
+ * will be available to consumers of metadata stored by the MediaMetadataEditor.
+ * @param key the identifier of a the metadata field to set. Valid values are
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
+ * expressed in milliseconds),
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+ * @param value The long value for the given key
+ * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+ * calls together.
+ * @throws IllegalArgumentException
+ */
+ public synchronized MediaMetadataEditor putLong(int key, long value)
+ throws IllegalArgumentException {
+ if (mApplied) {
+ Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+ return this;
+ }
+ if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
+ throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+ }
+ mEditorMetadata.putLong(String.valueOf(key), value);
+ mMetadataChanged = true;
+ return this;
+ }
+
+ /**
+ * Adds image.
+ * @param key the identifier of the bitmap to set. The only valid value is
+ * {@link #BITMAP_KEY_ARTWORK}
+ * @param bitmap The bitmap for the artwork, or null if there isn't any.
+ * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+ * calls together.
+ * @throws IllegalArgumentException
+ * @see android.graphics.Bitmap
+ */
+ public synchronized MediaMetadataEditor putBitmap(int key, Bitmap bitmap)
+ throws IllegalArgumentException {
+ if (mApplied) {
+ Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+ return this;
+ }
+ if (key != BITMAP_KEY_ARTWORK) {
+ throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
+ }
+ mEditorArtwork = bitmap;
+ mArtworkChanged = true;
+ return this;
+ }
+
+ /**
+ * Adds information stored as an instance.
+ * Note that none of the information added after {@link #apply()} has been called
+ * will be available to consumers of metadata stored by the MediaMetadataEditor.
+ * @param key the identifier of a the metadata field to set. Valid keys for a:
+ * <ul>
+ * <li>{@link Bitmap} object are {@link #BITMAP_KEY_ARTWORK},</li>
+ * <li>{@link String} object are the same as for {@link #putString(int, String)}</li>
+ * <li>{@link Long} object are the same as for {@link #putLong(int, long)}</li>
+ * <li>{@link Rating} object are {@link #RATING_KEY_BY_OTHERS}
+ * and {@link #RATING_KEY_BY_USER}.</li>
+ * </ul>
+ * @param value the metadata to add.
+ * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+ * calls together.
+ * @throws IllegalArgumentException
+ */
+ public synchronized MediaMetadataEditor putObject(int key, Object value)
+ throws IllegalArgumentException {
+ if (mApplied) {
+ Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+ return this;
+ }
+ switch(METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
+ case METADATA_TYPE_LONG:
+ if (value instanceof Long) {
+ return putLong(key, ((Long)value).longValue());
+ } else {
+ throw(new IllegalArgumentException("Not a non-null Long for key "+ key));
+ }
+ case METADATA_TYPE_STRING:
+ if ((value == null) || (value instanceof String)) {
+ return putString(key, (String) value);
+ } else {
+ throw(new IllegalArgumentException("Not a String for key "+ key));
+ }
+ case METADATA_TYPE_RATING:
+ mEditorMetadata.putParcelable(String.valueOf(key), (Parcelable)value);
+ mMetadataChanged = true;
+ break;
+ case METADATA_TYPE_BITMAP:
+ if ((value == null) || (value instanceof Bitmap)) {
+ return putBitmap(key, (Bitmap) value);
+ } else {
+ throw(new IllegalArgumentException("Not a Bitmap for key "+ key));
+ }
+ default:
+ throw(new IllegalArgumentException("Invalid key "+ key));
+ }
+ return this;
+ }
+
+
+ /**
+ * Returns the long value for the key.
+ * @param key one of the keys supported in {@link #putLong(int, long)}
+ * @param defaultValue the value returned if the key is not present
+ * @return the long value for the key, or the supplied default value if the key is not present
+ * @throws IllegalArgumentException
+ */
+ public synchronized long getLong(int key, long defaultValue)
+ throws IllegalArgumentException {
+ if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
+ throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+ }
+ return mEditorMetadata.getLong(String.valueOf(key), defaultValue);
+ }
+
+ /**
+ * Returns the {@link String} value for the key.
+ * @param key one of the keys supported in {@link #putString(int, String)}
+ * @param defaultValue the value returned if the key is not present
+ * @return the {@link String} value for the key, or the supplied default value if the key is
+ * not present
+ * @throws IllegalArgumentException
+ */
+ public synchronized String getString(int key, String defaultValue)
+ throws IllegalArgumentException {
+ if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
+ throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+ }
+ return mEditorMetadata.getString(String.valueOf(key), defaultValue);
+ }
+
+ /**
+ * Returns the {@link Bitmap} value for the key.
+ * @param key the {@link #BITMAP_KEY_ARTWORK} key
+ * @param defaultValue the value returned if the key is not present
+ * @return the {@link Bitmap} value for the key, or the supplied default value if the key is
+ * not present
+ * @throws IllegalArgumentException
+ */
+ public synchronized Bitmap getBitmap(int key, Bitmap defaultValue)
+ throws IllegalArgumentException {
+ if (key != BITMAP_KEY_ARTWORK) {
+ throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
+ }
+ return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
+ }
+
+ /**
+ * Returns an object representation of the value for the key
+ * @param key one of the keys supported in {@link #putObject(int, Object)}
+ * @param defaultValue the value returned if the key is not present
+ * @return the object for the key, as a {@link Long}, {@link Bitmap}, {@link String}, or
+ * {@link Rating} depending on the key value, or the supplied default value if the key is
+ * not present
+ * @throws IllegalArgumentException
+ */
+ public synchronized Object getObject(int key, Object defaultValue)
+ throws IllegalArgumentException {
+ switch (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
+ case METADATA_TYPE_LONG:
+ if (mEditorMetadata.containsKey(String.valueOf(key))) {
+ return mEditorMetadata.getLong(String.valueOf(key));
+ } else {
+ return defaultValue;
+ }
+ case METADATA_TYPE_STRING:
+ if (mEditorMetadata.containsKey(String.valueOf(key))) {
+ return mEditorMetadata.getString(String.valueOf(key));
+ } else {
+ return defaultValue;
+ }
+ case METADATA_TYPE_RATING:
+ if (mEditorMetadata.containsKey(String.valueOf(key))) {
+ return mEditorMetadata.getParcelable(String.valueOf(key));
+ } else {
+ return defaultValue;
+ }
+ case METADATA_TYPE_BITMAP:
+ // only one key for Bitmap supported, value is not stored in mEditorMetadata Bundle
+ if (key == BITMAP_KEY_ARTWORK) {
+ return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
+ } // else: fall through to invalid key handling
+ default:
+ throw(new IllegalArgumentException("Invalid key "+ key));
+ }
+ }
+
+
+ /**
+ * @hide
+ */
+ protected static final int METADATA_TYPE_INVALID = -1;
+ /**
+ * @hide
+ */
+ protected static final int METADATA_TYPE_LONG = 0;
+
+ /**
+ * @hide
+ */
+ protected static final int METADATA_TYPE_STRING = 1;
+
+ /**
+ * @hide
+ */
+ protected static final int METADATA_TYPE_BITMAP = 2;
+
+ /**
+ * @hide
+ */
+ protected static final int METADATA_TYPE_RATING = 3;
+
+ /**
+ * @hide
+ */
+ protected static final SparseIntArray METADATA_KEYS_TYPE;
+
+ static {
+ METADATA_KEYS_TYPE = new SparseIntArray(17);
+ // NOTE: if adding to the list below, make sure you increment the array initialization size
+ // keys with long values
+ METADATA_KEYS_TYPE.put(
+ MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, METADATA_TYPE_LONG);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_TYPE_LONG);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_TYPE_LONG);
+ // keys with String values
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(
+ MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(
+ MediaMetadataRetriever.METADATA_KEY_COMPILATION, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_TYPE_STRING);
+ // keys with Bitmap values
+ METADATA_KEYS_TYPE.put(BITMAP_KEY_ARTWORK, METADATA_TYPE_BITMAP);
+ // keys with Rating values
+ METADATA_KEYS_TYPE.put(RATING_KEY_BY_OTHERS, METADATA_TYPE_RATING);
+ METADATA_KEYS_TYPE.put(RATING_KEY_BY_USER, METADATA_TYPE_RATING);
+ }
+}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 7acf8af..deba2cc 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1606,9 +1606,9 @@
} else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
mFormat = MediaFormat.createSubtitleFormat(
MEDIA_MIMETYPE_TEXT_VTT, language);
- mFormat.setInteger(MediaFormat.KEY_AUTOSELECT, in.readInt());
- mFormat.setInteger(MediaFormat.KEY_DEFAULT, in.readInt());
- mFormat.setInteger(MediaFormat.KEY_FORCED, in.readInt());
+ mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
+ mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
+ mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
} else {
mFormat = new MediaFormat();
mFormat.setString(MediaFormat.KEY_LANGUAGE, language);
@@ -1638,9 +1638,9 @@
dest.writeString(getLanguage());
if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- dest.writeInt(mFormat.getInteger(MediaFormat.KEY_AUTOSELECT));
- dest.writeInt(mFormat.getInteger(MediaFormat.KEY_DEFAULT));
- dest.writeInt(mFormat.getInteger(MediaFormat.KEY_FORCED));
+ dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
+ dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
+ dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
}
}
@@ -1765,15 +1765,21 @@
@Override
public void onSubtitleTrackSelected(SubtitleTrack track) {
if (mSelectedSubtitleTrackIndex >= 0) {
- deselectTrack(mSelectedSubtitleTrackIndex);
+ try {
+ selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, false);
+ } catch (IllegalStateException e) {
+ }
+ mSelectedSubtitleTrackIndex = -1;
}
- mSelectedSubtitleTrackIndex = -1;
setOnSubtitleDataListener(null);
for (int i = 0; i < mInbandSubtitleTracks.length; i++) {
if (mInbandSubtitleTracks[i] == track) {
Log.v(TAG, "Selecting subtitle track " + i);
- selectTrack(i);
mSelectedSubtitleTrackIndex = i;
+ try {
+ selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
+ } catch (IllegalStateException e) {
+ }
setOnSubtitleDataListener(mSubtitleDataListener);
break;
}
@@ -2046,13 +2052,30 @@
private void selectOrDeselectTrack(int index, boolean select)
throws IllegalStateException {
- // ignore out-of-band tracks
- TrackInfo[] trackInfo = getInbandTrackInfo();
- if (index >= trackInfo.length &&
- index < trackInfo.length + mOutOfBandSubtitleTracks.size()) {
+ // handle subtitle track through subtitle controller
+ SubtitleTrack track = null;
+ if (index < mInbandSubtitleTracks.length) {
+ track = mInbandSubtitleTracks[index];
+ } else if (index < mInbandSubtitleTracks.length + mOutOfBandSubtitleTracks.size()) {
+ track = mOutOfBandSubtitleTracks.get(index - mInbandSubtitleTracks.length);
+ }
+
+ if (mSubtitleController != null && track != null) {
+ if (select) {
+ mSubtitleController.selectTrack(track);
+ } else if (mSubtitleController.getSelectedTrack() == track) {
+ mSubtitleController.selectTrack(null);
+ } else {
+ Log.w(TAG, "trying to deselect track that was not selected");
+ }
return;
}
+ selectOrDeselectInbandTrack(index, select);
+ }
+
+ private void selectOrDeselectInbandTrack(int index, boolean select)
+ throws IllegalStateException {
Parcel request = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
diff --git a/media/java/android/media/Rating.aidl b/media/java/android/media/Rating.aidl
new file mode 100644
index 0000000..1dc336a
--- /dev/null
+++ b/media/java/android/media/Rating.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 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 android.media;
+
+parcelable Rating;
diff --git a/media/java/android/media/Rating.java b/media/java/android/media/Rating.java
new file mode 100644
index 0000000..82c0392
--- /dev/null
+++ b/media/java/android/media/Rating.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2013 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 android.media;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class to encapsulate rating information used as content metadata.
+ * A rating is defined by its rating style (see {@link #RATING_HEART},
+ * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
+ * {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may
+ * be defined as "unrated"), both of which are defined when the rating instance is constructed
+ * through one of the factory methods.
+ */
+public final class Rating implements Parcelable {
+
+ private final static String TAG = "Rating";
+
+ /**
+ * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
+ * indicate the content referred to is a favorite (or not).
+ */
+ public final static int RATING_HEART = 1;
+
+ /**
+ * A rating style for "thumb up" vs "thumb down".
+ */
+ public final static int RATING_THUMB_UP_DOWN = 2;
+
+ /**
+ * A rating style with 0 to 3 stars.
+ */
+ public final static int RATING_3_STARS = 3;
+
+ /**
+ * A rating style with 0 to 4 stars.
+ */
+ public final static int RATING_4_STARS = 4;
+
+ /**
+ * A rating style with 0 to 5 stars.
+ */
+ public final static int RATING_5_STARS = 5;
+
+ /**
+ * A rating style expressed as a percentage.
+ */
+ public final static int RATING_PERCENTAGE = 6;
+
+ private final static float RATING_NOT_RATED = -1.0f;
+
+ private final int mRatingStyle;
+
+ private final float mRatingValue;
+
+ private Rating(int ratingStyle, float rating) {
+ mRatingStyle = ratingStyle;
+ mRatingValue = rating;
+ }
+
+
+ /**
+ * @hide
+ */
+ @Override
+ public String toString () {
+ return "Rating:style=" + mRatingStyle + " rating="
+ + (mRatingValue < 0.0f ? "unrated" : String.valueOf(mRatingValue));
+ }
+
+ @Override
+ public int describeContents() {
+ return mRatingStyle;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRatingStyle);
+ dest.writeFloat(mRatingValue);
+ }
+
+ public static final Parcelable.Creator<Rating> CREATOR
+ = new Parcelable.Creator<Rating>() {
+ /**
+ * Rebuilds a Rating previously stored with writeToParcel().
+ * @param p Parcel object to read the Rating from
+ * @return a new Rating created from the data in the parcel
+ */
+ public Rating createFromParcel(Parcel p) {
+ return new Rating(p.readInt(), p.readFloat());
+ }
+ public Rating[] newArray(int size) {
+ return new Rating[size];
+ }
+ };
+
+ /**
+ * Return a Rating instance with no rating.
+ * Create and return a new Rating instance with no rating known for the given
+ * rating style.
+ * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
+ * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
+ * or {@link #RATING_PERCENTAGE}.
+ * @return null if an invalid rating style is passed, a new Rating instance otherwise.
+ */
+ public static Rating newUnratedRating(int ratingStyle) {
+ switch(ratingStyle) {
+ case RATING_HEART:
+ case RATING_THUMB_UP_DOWN:
+ case RATING_3_STARS:
+ case RATING_4_STARS:
+ case RATING_5_STARS:
+ case RATING_PERCENTAGE:
+ return new Rating(ratingStyle, RATING_NOT_RATED);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Return a Rating instance with a heart-based rating.
+ * Create and return a new Rating instance with a rating style of {@link #RATING_HEART},
+ * and a heart-based rating.
+ * @param hasHeart true for a "heart selected" rating, false for "heart unselected".
+ * @return a new Rating instance.
+ */
+ public static Rating newHeartRating(boolean hasHeart) {
+ return new Rating(RATING_HEART, hasHeart ? 1.0f : 0.0f);
+ }
+
+ /**
+ * Return a Rating instance with a thumb-based rating.
+ * Create and return a new Rating instance with a {@link #RATING_THUMB_UP_DOWN}
+ * rating style, and a "thumb up" or "thumb down" rating.
+ * @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
+ * @return a new Rating instance.
+ */
+ public static Rating newThumbRating(boolean thumbIsUp) {
+ return new Rating(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f);
+ }
+
+ /**
+ * Return a Rating instance with a star-based rating.
+ * Create and return a new Rating instance with one of the star-base rating styles
+ * and the given integer or fractional number of stars. Non integer values can for instance
+ * be used to represent an average rating value, which might not be an integer number of stars.
+ * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
+ * {@link #RATING_5_STARS}.
+ * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to
+ * the rating style.
+ * @return null if the rating style is invalid, or the rating is out of range,
+ * a new Rating instance otherwise.
+ */
+ public static Rating newStarRating(int starRatingStyle, float starRating) {
+ float maxRating = -1.0f;
+ switch(starRatingStyle) {
+ case RATING_3_STARS:
+ maxRating = 3.0f;
+ break;
+ case RATING_4_STARS:
+ maxRating = 4.0f;
+ break;
+ case RATING_5_STARS:
+ maxRating = 5.0f;
+ break;
+ default:
+ Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
+ return null;
+ }
+ if ((starRating < 0.0f) || (starRating > maxRating)) {
+ Log.e(TAG, "Trying to set out of range star-based rating");
+ return null;
+ }
+ return new Rating(starRatingStyle, starRating);
+ }
+
+ /**
+ * Return a Rating instance with a percentage-based rating.
+ * Create and return a new Rating instance with a {@link #RATING_PERCENTAGE}
+ * rating style, and a rating of the given percentage.
+ * @param percent the value of the rating
+ * @return null if the rating is out of range, a new Rating instance otherwise.
+ */
+ public static Rating newPercentageRating(float percent) {
+ if ((percent < 0.0f) || (percent > 100.0f)) {
+ Log.e(TAG, "Invalid percentage-based rating value");
+ return null;
+ } else {
+ return new Rating(RATING_PERCENTAGE, percent);
+ }
+ }
+
+ /**
+ * Return whether there is a rating value available.
+ * @return true if the instance was not created with {@link #newUnratedRating(int)}.
+ */
+ public boolean isRated() {
+ return mRatingValue >= 0.0f;
+ }
+
+ /**
+ * Return the rating style.
+ * @return one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
+ * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
+ * or {@link #RATING_PERCENTAGE}.
+ */
+ public int getRatingStyle() {
+ return mRatingStyle;
+ }
+
+ /**
+ * Return whether the rating is "heart selected".
+ * @return true if the rating is "heart selected", false if the rating is "heart unselected",
+ * if the rating style is not {@link #RATING_HEART} or if it is unrated.
+ */
+ public boolean hasHeart() {
+ if (mRatingStyle != RATING_HEART) {
+ return false;
+ } else {
+ return (mRatingValue == 1.0f);
+ }
+ }
+
+ /**
+ * Return whether the rating is "thumb up".
+ * @return true if the rating is "thumb up", false if the rating is "thumb down",
+ * if the rating style is not {@link #RATING_THUMB_UP_DOWN} or if it is unrated.
+ */
+ public boolean isThumbUp() {
+ if (mRatingStyle != RATING_THUMB_UP_DOWN) {
+ return false;
+ } else {
+ return (mRatingValue == 1.0f);
+ }
+ }
+
+ /**
+ * Return the star-based rating value.
+ * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
+ * not star-based, or if it is unrated.
+ */
+ public float getStarRating() {
+ switch (mRatingStyle) {
+ case RATING_3_STARS:
+ case RATING_4_STARS:
+ case RATING_5_STARS:
+ if (isRated()) {
+ return mRatingValue;
+ }
+ default:
+ return -1.0f;
+ }
+ }
+
+ /**
+ * Return the percentage-based rating value.
+ * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
+ * not percentage-based, or if it is unrated.
+ */
+ public float getPercentRating() {
+ if ((mRatingStyle != RATING_PERCENTAGE) || !isRated()) {
+ return -1.0f;
+ } else {
+ return mRatingValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 58f5d55..7613c89 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -30,6 +30,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -297,8 +298,8 @@
* Flag indicating a RemoteControlClient supports ratings.
* This flag must be set in order for components that display the RemoteControlClient
* information, to display ratings information, and, if ratings are declared editable
- * (by calling {@link MetadataEditor#addEditableKey(int)} with the
- * {@link MetadataEditor#LONG_KEY_RATING_BY_USER} key), it will enable the user to rate
+ * (by calling {@link MediaMetadataEditor#addEditableKey(int)} with the
+ * {@link MediaMetadataEditor#RATING_KEY_BY_USER} key), it will enable the user to rate
* the media, with values being received through the interface set with
* {@link #setMetadataUpdateListener(OnMetadataUpdateListener)}.
* @see #setTransportControlFlags(int)
@@ -385,27 +386,6 @@
mEventHandler = new EventHandler(this, looper);
}
- private static final int[] METADATA_KEYS_TYPE_STRING = {
- MediaMetadataRetriever.METADATA_KEY_ALBUM,
- MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
- MediaMetadataRetriever.METADATA_KEY_TITLE,
- MediaMetadataRetriever.METADATA_KEY_ARTIST,
- MediaMetadataRetriever.METADATA_KEY_AUTHOR,
- MediaMetadataRetriever.METADATA_KEY_COMPILATION,
- MediaMetadataRetriever.METADATA_KEY_COMPOSER,
- MediaMetadataRetriever.METADATA_KEY_DATE,
- MediaMetadataRetriever.METADATA_KEY_GENRE,
- MediaMetadataRetriever.METADATA_KEY_TITLE,
- MediaMetadataRetriever.METADATA_KEY_WRITER };
- private static final int[] METADATA_KEYS_TYPE_LONG = {
- MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
- MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
- MediaMetadataRetriever.METADATA_KEY_DURATION,
- MediaMetadataRetriever.METADATA_KEY_YEAR,
- MetadataEditor.LONG_KEY_RATING_TYPE,
- MetadataEditor.LONG_KEY_RATING_BY_OTHERS,
- MetadataEditor.LONG_KEY_RATING_BY_USER};
-
/**
* Class used to modify metadata in a {@link RemoteControlClient} object.
* Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
@@ -414,28 +394,7 @@
* for the associated client. Once the metadata has been "applied", you cannot reuse this
* instance of the MetadataEditor.
*/
- public class MetadataEditor {
- /**
- * Mask of editable keys.
- */
- private long mEditableKeys;
- /**
- * @hide
- */
- protected boolean mMetadataChanged;
- /**
- * @hide
- */
- protected boolean mArtworkChanged;
- /**
- * @hide
- */
- protected Bitmap mEditorArtwork;
- /**
- * @hide
- */
- protected Bundle mEditorMetadata;
- private boolean mApplied = false;
+ public class MetadataEditor extends MediaMetadataEditor {
// only use RemoteControlClient.editMetadata() to get a MetadataEditor instance
private MetadataEditor() { }
@@ -450,73 +409,10 @@
* The metadata key for the content artwork / album art.
*/
public final static int BITMAP_KEY_ARTWORK = 100;
- /**
- * The metadata key qualifying the content rating.
- * The value associated with this key may be: {@link #RATING_HEART},
- * {@link #RATING_THUMB_UP_DOWN}, or a non-null positive integer expressing a maximum
- * number of "stars" for the rating, for which a typical value is 3 or 5.
- */
- public final static int LONG_KEY_RATING_TYPE = 101;
- /**
- * The metadata key for the content's average rating, not the user's rating.
- * The value associated with this key may be: an integer value between 0 and 100,
- * or {@link #RATING_NOT_RATED} to express that no average rating is available.
- * <p></p>
- * Note that a rating value up to 100 is not incompatible with a rating type using up
- * to 5 stars for instance, as the average may be an non-integer number of stars.
- * <p></p>
- * When the rating type is:
- * <ul>
- * <li>{@link #RATING_HEART}, a rating of 51 to 100 means "heart selected",</li>
- * <li>{@link #RATING_THUMB_UP_DOWN}, a rating of 0 to 50 means "thumb down",
- * 51 to 100 means "thumb up"</li>
- * <li>a non-null positive integer, the rating value is mapped to the number of stars, e.g.
- * with a maximum of 5 stars, a rating of 0 maps to 0 stars, 1 to 20 maps to 1 star,
- * 21 to 40 maps to 2 stars, etc.</li>
- * </ul>
- * @see #LONG_KEY_RATING_BY_USER
- */
- public final static int LONG_KEY_RATING_BY_OTHERS = 102;
-
- // editable keys
- /**
- * @hide
- * Editable key mask
- */
- public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF;
- /**
- * The metadata key for the content's user rating.
- * The value associated with this key may be: an integer value between 0 and 100,
- * or {@link #RATING_NOT_RATED} to express that the user hasn't rated this content.
- * Rules for the interpretation of the rating value according to the rating style are
- * the same as for {@link #LONG_KEY_RATING_BY_OTHERS}.
- * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable
- * receiving user rating values through the
- * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface.
- */
- public final static int LONG_KEY_RATING_BY_USER = 0x10000001;
-
- /**
- * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
- * indicate the content referred to is a favorite (or not).
- * @see #LONG_KEY_RATING_TYPE
- */
- public final static long RATING_HEART = -1;
- /**
- * A rating style for "thumb up" vs "thumb down".
- * @see #LONG_KEY_RATING_TYPE
- */
- public final static long RATING_THUMB_UP_DOWN = -2;
- /**
- * A rating value indicating no rating is available.
- * @see #LONG_KEY_RATING_BY_OTHERS
- * @see #LONG_KEY_RATING_BY_USER
- */
- public final static long RATING_NOT_RATED = -101;
/**
* @hide
- * TODO(jmtrivi) have lockscreen and music move to the new key name
+ * TODO(jmtrivi) have lockscreen move to the new key name and remove
*/
public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
@@ -543,15 +439,7 @@
*/
public synchronized MetadataEditor putString(int key, String value)
throws IllegalArgumentException {
- if (mApplied) {
- Log.e(TAG, "Can't edit a previously applied MetadataEditor");
- return this;
- }
- if (!validTypeForKey(key, METADATA_KEYS_TYPE_STRING)) {
- throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
- }
- mEditorMetadata.putString(String.valueOf(key), value);
- mMetadataChanged = true;
+ super.putString(key, value);
return this;
}
@@ -564,9 +452,7 @@
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
* expressed in milliseconds),
- * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR},
- * {@link #LONG_KEY_RATING_BY_OTHERS}, {@link #LONG_KEY_RATING_BY_USER},
- * {@link #LONG_KEY_RATING_TYPE}.
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
* @param value The long value for the given key
* @return Returns a reference to the same MetadataEditor object, so you can chain put
* calls together.
@@ -574,15 +460,7 @@
*/
public synchronized MetadataEditor putLong(int key, long value)
throws IllegalArgumentException {
- if (mApplied) {
- Log.e(TAG, "Can't edit a previously applied MetadataEditor");
- return this;
- }
- if (!validTypeForKey(key, METADATA_KEYS_TYPE_LONG)) {
- throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
- }
- mEditorMetadata.putLong(String.valueOf(key), value);
- mMetadataChanged = true;
+ super.putLong(key, value);
return this;
}
@@ -596,69 +474,22 @@
* @throws IllegalArgumentException
* @see android.graphics.Bitmap
*/
+ @Override
public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
throws IllegalArgumentException {
- if (mApplied) {
- Log.e(TAG, "Can't edit a previously applied MetadataEditor");
- return this;
- }
- if (key != BITMAP_KEY_ARTWORK) {
- throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
- }
- mEditorArtwork = bitmap;
- mArtworkChanged = true;
+ super.putBitmap(key, bitmap);
return this;
}
/**
- * Clears all the metadata that has been set since the MetadataEditor instance was
- * created with {@link RemoteControlClient#editMetadata(boolean)}.
+ * Clears all the metadata that has been set since the MetadataEditor instance was created
+ * (with {@link RemoteControlClient#editMetadata(boolean)}).
* Note that clearing the metadata doesn't reset the editable keys
- * (use {@link #clearEditableKeys()} instead).
+ * (use {@link MediaMetadataEditor#removeEditableKeys()} instead).
*/
+ @Override
public synchronized void clear() {
- if (mApplied) {
- Log.e(TAG, "Can't clear a previously applied MetadataEditor");
- return;
- }
- mEditorMetadata.clear();
- mEditorArtwork = null;
- }
-
- /**
- * Flag the given key as being editable.
- * This will declare the metadata field as eligible to be updated, with new values
- * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface.
- * @param key the type of metadata that can be edited. The supported key is
- * {@link #LONG_KEY_RATING_BY_USER}.
- */
- public synchronized void addEditableKey(int key) {
- if (mApplied) {
- Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor");
- return;
- }
- // only one editable key at the moment, so we're not wasting memory on an array
- // of editable keys to check the validity of the key, just hardcode the supported key.
- if (key == MetadataEditor.LONG_KEY_RATING_BY_USER) {
- mEditableKeys |= (MetadataEditor.KEY_EDITABLE_MASK & key);
- mMetadataChanged = true;
- } else {
- Log.e(TAG, "Metadata key " + key + " cannot be edited");
- }
- }
-
- /**
- * Causes all metadata fields to be read-only.
- */
- public synchronized void clearEditableKeys() {
- if (mApplied) {
- Log.e(TAG, "Can't clear editable keys of a previously applied MetadataEditor");
- return;
- }
- if (mEditableKeys != 0) {
- mEditableKeys = 0;
- mMetadataChanged = true;
- }
+ super.clear();
}
/**
@@ -881,30 +712,17 @@
/**
* Interface definition for a callback to be invoked when one of the metadata values has
* been updated.
+ * Implement this interface to receive metadata updates after registering your listener
+ * through {@link RemoteControlClient#setMetadataUpdateListener(OnMetadataUpdateListener)}.
*/
- public interface OnMetadataUpdateListener {
+ public interface OnMetadataUpdateListener {
/**
* Called on the implementer to notify that the metadata field for the given key has
- * been updated to the new value of type <code>long</long>.
- * @param key the identifier of the updated metadata field of type <code>long</long>.
- * @param newValue the new <code>long</long> value for the key
+ * been updated to the new value.
+ * @param key the identifier of the updated metadata field.
+ * @param newValue the Object storing the new value for the key.
*/
- void onMetadataUpdateLong(int key, long newValue);
- /**
- * Called on the implementer to notify that the metadata field for the given key has
- * been updated to the new <code>String</long>.
- * @param key the identifier of the updated metadata field of type <code>String</long>.
- * @param newValue the new <code>String</long> value for the key
- */
- void onMetadataUpdateString(int key, String newValue);
- /**
- * Called on the implementer to notify that the metadata field for the given key has
- * been updated to the new {@link android.graphics.Bitmap}.
- * @param key the identifier of the updated metadata field of type
- * {@link android.graphics.Bitmap}.
- * @param newValue the new {@link android.graphics.Bitmap} for the key
- */
- void onMetadataUpdateBitmap(int key, Bitmap newValue);
+ public abstract void onMetadataUpdate(int key, Object newValue);
}
/**
@@ -1338,12 +1156,11 @@
}
}
- public void updateMetadata(int generationId, int key, long value) {
+ public void updateMetadata(int generationId, int key, Rating value) {
// only post messages, we can't block here
if (mEventHandler != null) {
mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_UPDATE_METADATA_LONG, generationId /* arg1 */, key /* arg2*/,
- new Long(value)));
+ MSG_UPDATE_METADATA, generationId /* arg1 */, key /* arg2*/, value));
}
}
};
@@ -1389,7 +1206,7 @@
private final static int MSG_SEEK_TO = 10;
private final static int MSG_POSITION_DRIFT_CHECK = 11;
private final static int MSG_DISPLAY_WANTS_POS_SYNC = 12;
- private final static int MSG_UPDATE_METADATA_LONG = 13;
+ private final static int MSG_UPDATE_METADATA = 13;
private class EventHandler extends Handler {
public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1443,8 +1260,8 @@
case MSG_DISPLAY_WANTS_POS_SYNC:
onDisplayWantsSync((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
break;
- case MSG_UPDATE_METADATA_LONG:
- onUpdateMetadata(msg.arg1, msg.arg2, ((Long)msg.obj).longValue());
+ case MSG_UPDATE_METADATA:
+ onUpdateMetadata(msg.arg1, msg.arg2, msg.obj);
break;
default:
Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
@@ -1725,10 +1542,10 @@
}
}
- private void onUpdateMetadata(int generationId, int key, long value) {
+ private void onUpdateMetadata(int generationId, int key, Object value) {
synchronized (mCacheLock) {
if ((mCurrentClientGenId == generationId) && (mMetadataUpdateListener != null)) {
- mMetadataUpdateListener.onMetadataUpdateLong(key, value);
+ mMetadataUpdateListener.onMetadataUpdate(key, value);
}
}
}
@@ -1771,24 +1588,6 @@
return bitmap;
}
- /**
- * Fast routine to go through an array of allowed keys and return whether the key is part
- * of that array
- * @param key the key value
- * @param validKeys the array of valid keys for a given type
- * @return true if the key is part of the array, false otherwise
- */
- private static boolean validTypeForKey(int key, int[] validKeys) {
- try {
- for (int i = 0 ; ; i++) {
- if (key == validKeys[i]) {
- return true;
- }
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- return false;
- }
- }
/**
* Returns whether, for the given playback state, the playback position is expected to
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
new file mode 100644
index 0000000..6266160
--- /dev/null
+++ b/media/java/android/media/RemoteController.java
@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2013 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 android.media;
+
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.media.IRemoteControlDisplay;
+import android.media.MediaMetadataEditor;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.KeyEvent;
+
+/**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * The RemoteController class is used to control media playback, display and update media metadata
+ * and playback status, published by applications using the {@link RemoteControlClient} class.
+ * <p>
+ * A RemoteController shall be registered through
+ * {@link AudioManager#registerRemoteController(RemoteController)} in order for the system to send
+ * media event updates to the listener set in
+ * {@link #setOnClientUpdateListener(OnClientUpdateListener)}. This listener is a subclass of
+ * the {@link OnClientUpdateListener} abstract class. Override its methods to receive the
+ * information published by the active {@link RemoteControlClient} instances.
+ * By default an {@link OnClientUpdateListener} implementation will not receive bitmaps for album
+ * art. Use {@link #setBitmapConfiguration(boolean, int, int)} to receive images as well.
+ * <p>
+ * A RemoteController can also be used without being registered, when it is only meant to send
+ * media key events (for play or stop events for instance),
+ * with {@link #sendMediaKeyEvent(KeyEvent)}.
+ */
+public class RemoteController
+{
+ private final static int MAX_BITMAP_DIMENSION = 512;
+ private final static int TRANSPORT_UNKNOWN = 0;
+ private RcDisplay mRcd;
+ private final static String TAG = "RemoteController";
+ private final static boolean DEBUG = false;
+ private final static Object mGenLock = new Object();
+ private final static Object mInfoLock = new Object();
+ private Context mContext;
+ private AudioManager mAudioManager;
+ private MetadataEditor mMetadataEditor;
+
+ /**
+ * Synchronized on mGenLock
+ */
+ private int mClientGenerationIdCurrent = 0;
+
+ /**
+ * Synchronized on mInfoLock
+ */
+ private boolean mIsRegistered = false;
+ private PendingIntent mClientPendingIntentCurrent;
+ private OnClientUpdateListener mOnClientUpdateListener;
+ private PlaybackInfo mLastPlaybackInfo;
+ private int mLastTransportControlFlags = TRANSPORT_UNKNOWN;
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param ctxt non-null {@link Context}
+ * @throws java.lang.IllegalArgumentException
+ */
+ public RemoteController(Context ctxt) throws IllegalArgumentException {
+ if (ctxt == null) {
+ throw new IllegalArgumentException("Invalid null Context");
+ }
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else {
+ mEventHandler = null;
+ Log.e(TAG, "RemoteController() couldn't find main application thread");
+ }
+ mContext = ctxt;
+ mRcd = new RcDisplay();
+ mAudioManager = (AudioManager) ctxt.getSystemService(Context.AUDIO_SERVICE);
+ }
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param looper
+ * @param ctxt non-null {@link Context}
+ * @throws java.lang.IllegalArgumentException
+ */
+ public RemoteController(Looper looper, Context ctxt) throws IllegalArgumentException {
+ if (ctxt == null) {
+ throw new IllegalArgumentException("Invalid null Context");
+ }
+ mEventHandler = new EventHandler(this, looper);
+ mContext = ctxt;
+ mRcd = new RcDisplay();
+ mAudioManager = (AudioManager) ctxt.getSystemService(Context.AUDIO_SERVICE);
+ }
+
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ */
+ public static abstract class OnClientUpdateListener {
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param clearing
+ */
+ public void onClientReset(boolean clearing) { }
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param state
+ */
+ public void onClientPlaybackStateUpdate(int state) { }
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param state
+ * @param stateChangeTimeMs
+ * @param currentPosMs
+ * @param speed
+ */
+ public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs,
+ long currentPosMs, float speed) { }
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param transportControlFlags
+ * @param posCapabilities
+ */
+ public void onClientTransportControlUpdate(int transportControlFlags) { }
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param metadataEditor
+ */
+ public void onClientMetadataUpdate(MetadataEditor metadataEditor) { }
+ };
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param l
+ */
+ public void setOnClientUpdateListener(OnClientUpdateListener l) {
+ synchronized(mInfoLock) {
+ mOnClientUpdateListener = l;
+ if (!mIsRegistered) {
+ // since the object is not registered, it hasn't received any information from
+ // RemoteControlClients yet, so we can exit here.
+ return;
+ }
+ if (mLastPlaybackInfo != null) {
+ sendMsg(mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE,
+ mClientGenerationIdCurrent /*arg1*/, 0,
+ mLastPlaybackInfo /*obj*/, 0 /*delay*/);
+ }
+ if (mLastTransportControlFlags != TRANSPORT_UNKNOWN) {
+ sendMsg(mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE,
+ mClientGenerationIdCurrent /*arg1*/, mLastTransportControlFlags /*arg2*/,
+ null /*obj*/, 0 /*delay*/);
+ }
+ if (mMetadataEditor != null) {
+ sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+ mClientGenerationIdCurrent /*arg1*/, 0 /*arg2*/,
+ mMetadataEditor /*obj*/, 0 /*delay*/);
+ }
+ }
+ }
+
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Send a simulated key event for a media button.
+ * May be used without registering the RemoteController
+ * with {@link AudioManager#registerRemoteController(RemoteController)}. To simulate a key
+ * press, you must first send a KeyEvent built with a {@link KeyEvent#ACTION_DOWN} action, then
+ * another event with the {@link KeyEvent#ACTION_UP} action.
+ * <p> When used from a registered RemoteController, the key event will be sent to the
+ * application currently promoted to publish its media metadata and playback state (there may be
+ * none under some circumstances). With an unregistered RemoteController, the key event will be
+ * sent to the current media key event consumer
+ * (see {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}).
+ * @param keyEvent a {@link KeyEvent} instance whose key code is one of
+ * {@link KeyEvent.KEYCODE_MUTE},
+ * {@link KeyEvent.KEYCODE_HEADSETHOOK},
+ * {@link KeyEvent.KEYCODE_MEDIA_PLAY},
+ * {@link KeyEvent.KEYCODE_MEDIA_PAUSE},
+ * {@link KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE},
+ * {@link KeyEvent.KEYCODE_MEDIA_STOP},
+ * {@link KeyEvent.KEYCODE_MEDIA_NEXT},
+ * {@link KeyEvent.KEYCODE_MEDIA_PREVIOUS},
+ * {@link KeyEvent.KEYCODE_MEDIA_REWIND},
+ * {@link KeyEvent.KEYCODE_MEDIA_RECORD},
+ * {@link KeyEvent.KEYCODE_MEDIA_FAST_FORWARD},
+ * {@link KeyEvent.KEYCODE_MEDIA_CLOSE},
+ * {@link KeyEvent.KEYCODE_MEDIA_EJECT},
+ * or {@link KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK}.
+ */
+ public int sendMediaKeyEvent(KeyEvent keyEvent) {
+ if (!MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode())) {
+ Log.e(TAG, "Cannot use sendMediaKeyEvent() for a non-media key event");
+ return ERROR_BAD_VALUE;
+ }
+ boolean registered = false;
+ final PendingIntent pi;
+ synchronized(mInfoLock) {
+ registered = mIsRegistered;
+ pi = mClientPendingIntentCurrent;
+ }
+ if (registered) {
+ if (pi != null) {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ try {
+ pi.send(mContext, 0, intent);
+ } catch (CanceledException e) {
+ Log.e(TAG, "Error sending intent for media button down: ", e);
+ return ERROR;
+ }
+ } else {
+ Log.i(TAG, "No-op when sending key click, no receiver right now");
+ return ERROR;
+ }
+ } else {
+ mAudioManager.dispatchMediaKeyEvent(keyEvent);
+ }
+ return SUCCESS;
+ }
+
+
+ // Error codes
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Successful operation.
+ */
+ public static final int SUCCESS = 0;
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Unspecified error.
+ */
+ public static final int ERROR = -1;
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Operation failed due to bad parameter value.
+ */
+ public static final int ERROR_BAD_VALUE = -2;
+
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * @param timeMs
+ * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+ */
+ public int seekTo(long timeMs) {
+ if (timeMs < 0) {
+ return ERROR_BAD_VALUE;
+ }
+ final int genId;
+ synchronized (mGenLock) {
+ genId = mClientGenerationIdCurrent;
+ }
+ mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
+ return SUCCESS;
+ }
+
+
+ /**
+ * @hide
+ * must be called on a registered RemoteController
+ * @param wantBitmap
+ * @param width
+ * @param height
+ * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+ */
+ public int setBitmapConfiguration(boolean wantBitmap, int width, int height) {
+ synchronized (mInfoLock) {
+ if (!mIsRegistered) {
+ Log.e(TAG, "Cannot specify bitmap configuration on unregistered RemoteController");
+ return ERROR;
+ }
+ }
+ if (wantBitmap) {
+ if ((width > 0) && (height > 0)) {
+ if (width > MAX_BITMAP_DIMENSION) { width = MAX_BITMAP_DIMENSION; }
+ if (height > MAX_BITMAP_DIMENSION) { height = MAX_BITMAP_DIMENSION; }
+ mAudioManager.remoteControlDisplayUsesBitmapSize(mRcd, width, height);
+ } else {
+ Log.e(TAG, "Invalid dimensions");
+ return ERROR_BAD_VALUE;
+ }
+ } else {
+ mAudioManager.remoteControlDisplayUsesBitmapSize(mRcd, -1, -1);
+ }
+ return SUCCESS;
+ }
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * must be called on a registered RemoteController
+ * @param width
+ * @param height
+ * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+ */
+ public int setBitmapConfiguration(int width, int height) {
+ return setBitmapConfiguration(true, width, height);
+ }
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * must be called on a registered RemoteController
+ * @return {@link #SUCCESS}, {@link #ERROR}
+ */
+ public int setBitmapConfigurationNone() {
+ return setBitmapConfiguration(false, -1, -1);
+ }
+
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Default playback position synchronization mode where the RemoteControlClient is not
+ * asked regularly for its playback position to see if it has drifted from the estimated
+ * position.
+ */
+ public static final int POSITION_SYNCHRONIZATION_NONE = 0;
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * The playback position synchronization mode where the RemoteControlClient instances which
+ * expose their playback position to the framework, will be regularly polled to check
+ * whether any drift has been noticed between their estimated position and the one they report.
+ * Note that this mode should only ever be used when needing to display very accurate playback
+ * position, as regularly polling a RemoteControlClient for its position may have an impact
+ * on battery life (if applicable) when this query will trigger network transactions in the
+ * case of remote playback.
+ */
+ public static final int POSITION_SYNCHRONIZATION_CHECK = 1;
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Set the playback position synchronization mode.
+ * Must be called on a registered RemoteController.
+ * @param sync {@link #POSITION_SYNCHRONIZATION_NONE} or {@link #POSITION_SYNCHRONIZATION_CHECK}
+ * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+ */
+ public int setSynchronizationMode(int sync) {
+ if ((sync != POSITION_SYNCHRONIZATION_NONE) || (sync != POSITION_SYNCHRONIZATION_CHECK)) {
+ Log.e(TAG, "Unknown synchronization mode");
+ return ERROR_BAD_VALUE;
+ }
+ if (!mIsRegistered) {
+ Log.e(TAG, "Cannot set synchronization mode on an unregistered RemoteController");
+ return ERROR;
+ }
+ mAudioManager.remoteControlDisplayWantsPlaybackPositionSync(mRcd,
+ POSITION_SYNCHRONIZATION_CHECK == sync);
+ return SUCCESS;
+ }
+
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Creates a {@link MetadataEditor} for updating metadata values of the editable keys of
+ * the current {@link RemoteControlClient}.
+ * @return a new MetadataEditor instance.
+ */
+ public MetadataEditor editMetadata() {
+ MetadataEditor editor = new MetadataEditor();
+ editor.mEditorMetadata = new Bundle();
+ editor.mEditorArtwork = null;
+ editor.mMetadataChanged = true;
+ editor.mArtworkChanged = true;
+ editor.mEditableKeys = 0;
+ return editor;
+ }
+
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Used to read the metadata published by a {@link RemoteControlClient}, or send a
+ * {@link RemoteControlClient} new values for keys that can be edited.
+ */
+ public class MetadataEditor extends MediaMetadataEditor {
+ /**
+ * @hide
+ */
+ protected MetadataEditor() { }
+
+ /**
+ * @hide
+ */
+ protected MetadataEditor(Bundle metadata, long editableKeys) {
+ mEditorMetadata = metadata;
+ mEditableKeys = editableKeys;
+ mEditorArtwork = null;
+ mMetadataChanged = true;
+ mArtworkChanged = true;
+ mApplied = false;
+ }
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ */
+ public synchronized void apply() {
+ // "applying" a metadata bundle in RemoteController is only for sending edited
+ // key values back to the RemoteControlClient, so here we only care about the only
+ // editable key we support: RATING_KEY_BY_USER
+ if (!mMetadataChanged) {
+ return;
+ }
+ final int genId;
+ synchronized(mGenLock) {
+ genId = mClientGenerationIdCurrent;
+ }
+ synchronized(mInfoLock) {
+ if (mEditorMetadata.containsKey(
+ String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
+ Rating rating = (Rating) getObject(
+ MediaMetadataEditor.RATING_KEY_BY_USER, null);
+ mAudioManager.updateRemoteControlClientMetadata(genId,
+ MediaMetadataEditor.RATING_KEY_BY_USER,
+ rating);
+ } else {
+ Log.e(TAG, "no metadata to apply");
+ }
+ // NOT setting mApplied to true as this type of MetadataEditor will be applied
+ // multiple times, whenever the user of a RemoteController needs to change the
+ // metadata (e.g. user changes the rating of a song more than once during playback)
+ mApplied = false;
+ }
+ }
+
+ }
+
+
+ //==================================================
+ // Implementation of IRemoteControlDisplay interface
+ private class RcDisplay extends IRemoteControlDisplay.Stub {
+ /**
+ * @hide
+ */
+ public void setCurrentClientId(int genId, PendingIntent clientMediaIntent,
+ boolean clearing) {
+ boolean isNew = false;
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ mClientGenerationIdCurrent = genId;
+ isNew = true;
+ }
+ }
+ if (clientMediaIntent != null) {
+ sendMsg(mEventHandler, MSG_NEW_PENDING_INTENT, SENDMSG_REPLACE,
+ genId /*arg1*/, 0, clientMediaIntent /*obj*/, 0 /*delay*/);
+ }
+ if (isNew || clearing) {
+ sendMsg(mEventHandler, MSG_CLIENT_RESET, SENDMSG_REPLACE,
+ genId /*arg1*/, clearing ? 1 : 0, null /*obj*/, 0 /*delay*/);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setPlaybackState(int genId, int state,
+ long stateChangeTimeMs, long currentPosMs, float speed) {
+ if (DEBUG) {
+ Log.d(TAG, "> new playback state: genId="+genId
+ + " state="+ state
+ + " changeTime="+ stateChangeTimeMs
+ + " pos=" + currentPosMs
+ + "ms speed=" + speed);
+ }
+
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ return;
+ }
+ }
+ final PlaybackInfo playbackInfo =
+ new PlaybackInfo(state, stateChangeTimeMs, currentPosMs, speed);
+ sendMsg(mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE,
+ genId /*arg1*/, 0, playbackInfo /*obj*/, 0 /*delay*/);
+
+ }
+
+ /**
+ * @hide
+ */
+ public void setTransportControlInfo(int genId, int transportControlFlags,
+ int posCapabilities) {
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ return;
+ }
+ }
+ sendMsg(mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE,
+ genId /*arg1*/, transportControlFlags /*arg2*/,
+ null /*obj*/, 0 /*delay*/);
+ }
+
+ /**
+ * @hide
+ */
+ public void setMetadata(int genId, Bundle metadata) {
+ if (DEBUG) { Log.e(TAG, "setMetadata("+genId+")"); }
+ if (metadata == null) {
+ return;
+ }
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ return;
+ }
+ }
+ sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+ genId /*arg1*/, 0 /*arg2*/,
+ metadata /*obj*/, 0 /*delay*/);
+ }
+
+ /**
+ * @hide
+ */
+ public void setArtwork(int genId, Bitmap artwork) {
+ if (DEBUG) { Log.v(TAG, "setArtwork("+genId+")"); }
+ if (artwork == null) {
+ return;
+ }
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ return;
+ }
+ }
+ Bundle metadata = new Bundle(1);
+ metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), artwork);
+ sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+ genId /*arg1*/, 0 /*arg2*/,
+ metadata /*obj*/, 0 /*delay*/);
+ }
+
+ /**
+ * @hide
+ */
+ public void setAllMetadata(int genId, Bundle metadata, Bitmap artwork) {
+ if (DEBUG) { Log.e(TAG, "setAllMetadata("+genId+")"); }
+ if ((metadata == null) && (artwork == null)) {
+ return;
+ }
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ return;
+ }
+ }
+ if (metadata == null) {
+ metadata = new Bundle(1);
+ }
+ if (artwork != null) {
+ metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
+ artwork);
+ }
+ sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+ genId /*arg1*/, 0 /*arg2*/,
+ metadata /*obj*/, 0 /*delay*/);
+ }
+ }
+
+ //==================================================
+ // Event handling
+ private EventHandler mEventHandler;
+ private final static int MSG_NEW_PENDING_INTENT = 0;
+ private final static int MSG_NEW_PLAYBACK_INFO = 1;
+ private final static int MSG_NEW_TRANSPORT_INFO = 2;
+ private final static int MSG_NEW_METADATA = 3; // msg always has non-null obj parameter
+ private final static int MSG_CLIENT_RESET = 4;
+
+ private class EventHandler extends Handler {
+
+ public EventHandler(RemoteController rc, Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case MSG_NEW_PENDING_INTENT:
+ onNewPendingIntent(msg.arg1, (PendingIntent) msg.obj);
+ break;
+ case MSG_NEW_PLAYBACK_INFO:
+ onNewPlaybackInfo(msg.arg1, (PlaybackInfo) msg.obj);
+ break;
+ case MSG_NEW_TRANSPORT_INFO:
+ onNewTransportInfo(msg.arg1, msg.arg2);
+ break;
+ case MSG_NEW_METADATA:
+ onNewMetadata(msg.arg1, (Bundle)msg.obj);
+ break;
+ case MSG_CLIENT_RESET:
+ onClientReset(msg.arg1, msg.arg2 == 1);
+ break;
+ default:
+ Log.e(TAG, "unknown event " + msg.what);
+ }
+ }
+ }
+
+ /** If the msg is already queued, replace it with this one. */
+ private static final int SENDMSG_REPLACE = 0;
+ /** If the msg is already queued, ignore this one and leave the old. */
+ private static final int SENDMSG_NOOP = 1;
+ /** If the msg is already queued, queue this one and leave the old. */
+ private static final int SENDMSG_QUEUE = 2;
+
+ private static void sendMsg(Handler handler, int msg, int existingMsgPolicy,
+ int arg1, int arg2, Object obj, int delayMs) {
+ if (handler == null) {
+ Log.e(TAG, "null event handler, will not deliver message " + msg);
+ return;
+ }
+ if (existingMsgPolicy == SENDMSG_REPLACE) {
+ handler.removeMessages(msg);
+ } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
+ return;
+ }
+ handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delayMs);
+ }
+
+ private void onNewPendingIntent(int genId, PendingIntent pi) {
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ return;
+ }
+ }
+ synchronized(mInfoLock) {
+ mClientPendingIntentCurrent = pi;
+ }
+ }
+
+ private void onNewPlaybackInfo(int genId, PlaybackInfo pi) {
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ return;
+ }
+ }
+ final OnClientUpdateListener l;
+ synchronized(mInfoLock) {
+ l = this.mOnClientUpdateListener;
+ mLastPlaybackInfo = pi;
+ }
+ if (l != null) {
+ if (pi.mCurrentPosMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
+ l.onClientPlaybackStateUpdate(pi.mState);
+ } else {
+ l.onClientPlaybackStateUpdate(pi.mState, pi.mStateChangeTimeMs, pi.mCurrentPosMs,
+ pi.mSpeed);
+ }
+ }
+ }
+
+ private void onNewTransportInfo(int genId, int transportControlFlags) {
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ return;
+ }
+ }
+ final OnClientUpdateListener l;
+ synchronized(mInfoLock) {
+ l = mOnClientUpdateListener;
+ mLastTransportControlFlags = transportControlFlags;
+ }
+ if (l != null) {
+ l.onClientTransportControlUpdate(transportControlFlags);
+ }
+ }
+
+ /**
+ * @param genId
+ * @param metadata guaranteed to be always non-null
+ */
+ private void onNewMetadata(int genId, Bundle metadata) {
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ return;
+ }
+ }
+ final OnClientUpdateListener l;
+ final MetadataEditor metadataEditor;
+ // prepare the received Bundle to be used inside a MetadataEditor
+ final long editableKeys = metadata.getLong(
+ String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK), 0);
+ if (editableKeys != 0) {
+ metadata.remove(String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK));
+ }
+ synchronized(mInfoLock) {
+ l = mOnClientUpdateListener;
+ if ((mMetadataEditor != null) && (mMetadataEditor.mEditorMetadata != null)) {
+ if (mMetadataEditor.mEditorMetadata != metadata) {
+ // existing metadata, merge existing and new
+ mMetadataEditor.mEditorMetadata.putAll(metadata);
+ }
+ } else {
+ mMetadataEditor = new MetadataEditor(metadata, editableKeys);
+ }
+ metadataEditor = mMetadataEditor;
+ }
+ if (l != null) {
+ l.onClientMetadataUpdate(metadataEditor);
+ }
+ }
+
+ private void onClientReset(int genId, boolean clearing) {
+ synchronized(mGenLock) {
+ if (mClientGenerationIdCurrent != genId) {
+ return;
+ }
+ }
+ final OnClientUpdateListener l;
+ synchronized(mInfoLock) {
+ l = mOnClientUpdateListener;
+ }
+ if (l != null) {
+ l.onClientReset(clearing);
+ }
+ }
+
+
+ //==================================================
+ private static class PlaybackInfo {
+ int mState;
+ long mStateChangeTimeMs;
+ long mCurrentPosMs;
+ float mSpeed;
+
+ PlaybackInfo(int state, long stateChangeTimeMs, long currentPosMs, float speed) {
+ mState = state;
+ mStateChangeTimeMs = stateChangeTimeMs;
+ mCurrentPosMs = currentPosMs;
+ mSpeed = speed;
+ }
+ }
+
+ /**
+ * @hide
+ * Used by AudioManager to mark this instance as registered.
+ * @param registered
+ */
+ protected void setIsRegistered(boolean registered) {
+ synchronized (mInfoLock) {
+ mIsRegistered = registered;
+ }
+ }
+
+ /**
+ * @hide
+ * Used by AudioManager to access binder to be registered/unregistered inside MediaFocusControl
+ * @return
+ */
+ protected RcDisplay getRcDisplay() {
+ return mRcd;
+ }
+}
diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java
index e83c5ba..8090561 100644
--- a/media/java/android/media/SubtitleController.java
+++ b/media/java/android/media/SubtitleController.java
@@ -38,6 +38,21 @@
private boolean mShowing;
private CaptioningManager mCaptioningManager;
+ private CaptioningManager.CaptioningChangeListener mCaptioningChangeListener =
+ new CaptioningManager.CaptioningChangeListener() {
+ /** @hide */
+ @Override
+ public void onEnabledChanged(boolean enabled) {
+ selectDefaultTrack();
+ }
+
+ /** @hide */
+ @Override
+ public void onLocaleChanged(Locale locale) {
+ selectDefaultTrack();
+ }
+ };
+
/**
* Creates a subtitle controller for a media playback object that implements
* the MediaTimeProvider interface.
@@ -58,15 +73,24 @@
(CaptioningManager)context.getSystemService(Context.CAPTIONING_SERVICE);
}
+ @Override
+ protected void finalize() throws Throwable {
+ mCaptioningManager.removeCaptioningChangeListener(
+ mCaptioningChangeListener);
+ super.finalize();
+ }
+
/**
* @return the available subtitle tracks for this media. These include
* the tracks found by {@link MediaPlayer} as well as any tracks added
* manually via {@link #addTrack}.
*/
public SubtitleTrack[] getTracks() {
- SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
- mTracks.toArray(tracks);
- return tracks;
+ synchronized(mTracks) {
+ SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
+ mTracks.toArray(tracks);
+ return tracks;
+ }
}
/**
@@ -88,6 +112,8 @@
* in-band data from the {@link MediaPlayer}. However, this does
* not change the subtitle visibility.
*
+ * Must be called from the UI thread.
+ *
* @param track The subtitle track to select. This must be one of the
* tracks in {@link #getTracks}.
* @return true if the track was successfully selected.
@@ -107,7 +133,9 @@
}
mSelectedTrack = track;
- mAnchor.setSubtitleWidget(getRenderingWidget());
+ if (mAnchor != null) {
+ mAnchor.setSubtitleWidget(getRenderingWidget());
+ }
if (mSelectedTrack != null) {
mSelectedTrack.setTimeProvider(mTimeProvider);
@@ -123,56 +151,123 @@
/**
* @return the default subtitle track based on system preferences, or null,
* if no such track exists in this manager.
+ *
+ * Supports HLS-flags: AUTOSELECT, FORCED & DEFAULT.
+ *
+ * 1. If captioning is disabled, only consider FORCED tracks. Otherwise,
+ * consider all tracks, but prefer non-FORCED ones.
+ * 2. If user selected "Default" caption language:
+ * a. If there is a considered track with DEFAULT=yes, returns that track
+ * (favor the first one in the current language if there are more than
+ * one default tracks, or the first in general if none of them are in
+ * the current language).
+ * b. Otherwise, if there is a track with AUTOSELECT=yes in the current
+ * language, return that one.
+ * c. If there are no default tracks, and no autoselectable tracks in the
+ * current language, return null.
+ * 3. If there is a track with the caption language, select that one. Prefer
+ * the one with AUTOSELECT=no.
+ *
+ * The default values for these flags are DEFAULT=no, AUTOSELECT=yes
+ * and FORCED=no.
+ *
+ * Must be called from the UI thread.
*/
public SubtitleTrack getDefaultTrack() {
- Locale locale = mCaptioningManager.getLocale();
+ SubtitleTrack bestTrack = null;
+ int bestScore = -1;
- for (SubtitleTrack track: mTracks) {
- MediaFormat format = track.getFormat();
- String language = format.getString(MediaFormat.KEY_LANGUAGE);
- // TODO: select track with best renderer. For now, we select first
- // track with local's language or first track if locale has none
- if (locale == null ||
- locale.getLanguage().equals("") ||
- locale.getISO3Language().equals(language) ||
- locale.getLanguage().equals(language)) {
- return track;
+ Locale selectedLocale = mCaptioningManager.getLocale();
+ Locale locale = selectedLocale;
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ boolean selectForced = !mCaptioningManager.isEnabled();
+
+ synchronized(mTracks) {
+ for (SubtitleTrack track: mTracks) {
+ MediaFormat format = track.getFormat();
+ String language = format.getString(MediaFormat.KEY_LANGUAGE);
+ boolean forced =
+ format.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0;
+ boolean autoselect =
+ format.getInteger(MediaFormat.KEY_IS_AUTOSELECT, 1) != 0;
+ boolean is_default =
+ format.getInteger(MediaFormat.KEY_IS_DEFAULT, 0) != 0;
+
+ boolean languageMatches =
+ (locale == null ||
+ locale.getLanguage().equals("") ||
+ locale.getISO3Language().equals(language) ||
+ locale.getLanguage().equals(language));
+ // is_default is meaningless unless caption language is 'default'
+ int score = (forced ? 0 : 8) +
+ (((selectedLocale == null) && is_default) ? 4 : 0) +
+ (autoselect ? 0 : 2) + (languageMatches ? 1 : 0);
+
+ if (selectForced && !forced) {
+ continue;
+ }
+
+ // we treat null locale/language as matching any language
+ if ((selectedLocale == null && is_default) ||
+ (languageMatches &&
+ (autoselect || forced || selectedLocale != null))) {
+ if (score > bestScore) {
+ bestScore = score;
+ bestTrack = track;
+ }
+ }
}
}
- return null;
+ return bestTrack;
}
private boolean mTrackIsExplicit = false;
private boolean mVisibilityIsExplicit = false;
- /** @hide */
+ /** @hide - called from UI thread */
public void selectDefaultTrack() {
if (mTrackIsExplicit) {
- return;
- }
-
- SubtitleTrack track = getDefaultTrack();
- if (track != null) {
- selectTrack(track);
- mTrackIsExplicit = false;
+ // If track selection is explicit, but visibility
+ // is not, it falls back to the captioning setting
if (!mVisibilityIsExplicit) {
- if (mCaptioningManager.isEnabled()) {
+ if (mCaptioningManager.isEnabled() ||
+ (mSelectedTrack != null &&
+ mSelectedTrack.getFormat().getInteger(
+ MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
show();
} else {
hide();
}
mVisibilityIsExplicit = false;
}
+ return;
+ }
+
+ // We can have a default (forced) track even if captioning
+ // is not enabled. This is handled by getDefaultTrack().
+ // Show this track unless subtitles were explicitly hidden.
+ SubtitleTrack track = getDefaultTrack();
+ if (track != null) {
+ selectTrack(track);
+ mTrackIsExplicit = false;
+ if (!mVisibilityIsExplicit) {
+ show();
+ mVisibilityIsExplicit = false;
+ }
}
}
- /** @hide */
+ /** @hide - called from UI thread */
public void reset() {
hide();
selectTrack(null);
mTracks.clear();
mTrackIsExplicit = false;
mVisibilityIsExplicit = false;
+ mCaptioningManager.removeCaptioningChangeListener(
+ mCaptioningChangeListener);
}
/**
@@ -183,12 +278,20 @@
* @return the created {@link SubtitleTrack} object
*/
public SubtitleTrack addTrack(MediaFormat format) {
- for (Renderer renderer: mRenderers) {
- if (renderer.supports(format)) {
- SubtitleTrack track = renderer.createTrack(format);
- if (track != null) {
- mTracks.add(track);
- return track;
+ synchronized(mRenderers) {
+ for (Renderer renderer: mRenderers) {
+ if (renderer.supports(format)) {
+ SubtitleTrack track = renderer.createTrack(format);
+ if (track != null) {
+ synchronized(mTracks) {
+ if (mTracks.size() == 0) {
+ mCaptioningManager.addCaptioningChangeListener(
+ mCaptioningChangeListener);
+ }
+ mTracks.add(track);
+ }
+ return track;
+ }
}
}
}
@@ -197,6 +300,8 @@
/**
* Show the selected (or default) subtitle track.
+ *
+ * Must be called from the UI thread.
*/
public void show() {
mShowing = true;
@@ -208,6 +313,8 @@
/**
* Hide the selected (or default) subtitle track.
+ *
+ * Must be called from the UI thread.
*/
public void hide() {
mVisibilityIsExplicit = true;
@@ -257,10 +364,12 @@
* support for a subtitle format.
*/
public void registerRenderer(Renderer renderer) {
- // TODO how to get available renderers in the system
- if (!mRenderers.contains(renderer)) {
- // TODO should added renderers override existing ones (to allow replacing?)
- mRenderers.add(renderer);
+ synchronized(mRenderers) {
+ // TODO how to get available renderers in the system
+ if (!mRenderers.contains(renderer)) {
+ // TODO should added renderers override existing ones (to allow replacing?)
+ mRenderers.add(renderer);
+ }
}
}
@@ -279,7 +388,7 @@
private Anchor mAnchor;
- /** @hide */
+ /** @hide - called from UI thread */
public void setAnchor(Anchor anchor) {
if (mAnchor == anchor) {
return;
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index cb689af..06063de 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -69,7 +69,7 @@
}
/** @hide */
- public MediaFormat getFormat() {
+ public final MediaFormat getFormat() {
return mFormat;
}
@@ -201,7 +201,7 @@
}
/** @hide */
- public void scheduleTimedEvents() {
+ protected void scheduleTimedEvents() {
/* get times for the next event */
if (mTimeProvider != null) {
mNextScheduledTimeMs = mCues.nextTimeAfter(mLastTimeMs);
@@ -363,7 +363,7 @@
}
/** @hide */
- public void setTimeProvider(MediaTimeProvider timeProvider) {
+ public synchronized void setTimeProvider(MediaTimeProvider timeProvider) {
if (mTimeProvider == timeProvider) {
return;
}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index a03dbf3..0030dbd 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -721,13 +721,18 @@
return ACQUIRE_NO_BUFFERS;
}
+ if (buffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+ jniThrowException(env, "java/lang/UnsupportedOperationException",
+ "NV21 format is not supported by ImageReader");
+ return -1;
+ }
+
// Check if the left-top corner of the crop rect is origin, we currently assume this point is
// zero, will revist this once this assumption turns out problematic.
Point lt = buffer->crop.leftTop();
if (lt.x != 0 || lt.y != 0) {
- ALOGE("crop left: %d, top = %d", lt.x, lt.y);
- jniThrowException(env, "java/lang/UnsupportedOperationException",
- "crop left top corner need to at origin");
+ jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+ "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
return -1;
}
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 7d77c48..c05d527 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -37,6 +37,7 @@
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
<uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+ <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
<application android:label="@string/app_name"
android:process="com.android.systemui"
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 6badaaf..8cdcb7a 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -102,6 +102,8 @@
== TelephonyManager.CALL_STATE_OFFHOOK) {
mLockPatternUtils.resumeCall();
} else {
+ final boolean bypassHandler = true;
+ KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(bypassHandler);
Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
index 3e499b2..c2cd32f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
@@ -295,6 +295,13 @@
}
}
}
+
+ @Override
+ public void onEmergencyCallAction() {
+ if (mBiometricUnlock != null) {
+ mBiometricUnlock.stop();
+ }
+ }
};
@Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index dcec654..f4bbf9a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -91,6 +91,7 @@
private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
protected static final int MSG_SET_PLAYBACK_STATE = 316;
protected static final int MSG_USER_INFO_CHANGED = 317;
+ protected static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
private static KeyguardUpdateMonitor sInstance;
@@ -181,6 +182,9 @@
case MSG_USER_INFO_CHANGED:
handleUserInfoChanged(msg.arg1);
break;
+ case MSG_REPORT_EMERGENCY_CALL_ACTION:
+ handleReportEmergencyCallAction();
+ break;
}
}
};
@@ -758,6 +762,18 @@
}
}
+ /**
+ * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
+ */
+ private void handleReportEmergencyCallAction() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onEmergencyCallAction();
+ }
+ }
+ }
+
public boolean isKeyguardVisible() {
return mKeyguardIsVisible;
}
@@ -902,6 +918,22 @@
handleSimStateChange(new SimArgs(IccCardConstants.State.READY));
}
+ /**
+ * Report that the emergency call button has been pressed and the emergency dialer is
+ * about to be displayed.
+ *
+ * @param bypassHandler runs immediately.
+ *
+ * NOTE: Must be called from UI thread if bypassHandler == true.
+ */
+ public void reportEmergencyCallAction(boolean bypassHandler) {
+ if (!bypassHandler) {
+ mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget();
+ } else {
+ handleReportEmergencyCallAction();
+ }
+ }
+
public CharSequence getTelephonyPlmn() {
return mTelephonyPlmn;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 30b43f5..b0511e5 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -131,4 +131,8 @@
*/
public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { }
+ /**
+ * Called when the emergency call button is pressed.
+ */
+ void onEmergencyCallAction() { }
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 4333aea..8ab4645 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -414,12 +414,25 @@
// write anything and wait for the user to fix the range which will
// trigger an update.
mRequestedPages = mEditor.getRequestedPages();
- if (mRequestedPages == null) {
+ if (mRequestedPages == null || mRequestedPages.length == 0) {
mEditor.updateUi();
if (mEditor.isDone()) {
PrintJobConfigActivity.this.finish();
}
return;
+ } else {
+ // If print is not confirmed we just ask for the first of the
+ // selected pages to emulate a behavior that shows preview
+ // increasing the chances that apps will implement the APIs
+ // correctly.
+ if (!mEditor.isPrintConfirmed()) {
+ if (ALL_PAGES_ARRAY.equals(mRequestedPages)) {
+ mRequestedPages = new PageRange[] {new PageRange(0, 0)};
+ } else {
+ final int firstPage = mRequestedPages[0].getStart();
+ mRequestedPages = new PageRange[] {new PageRange(firstPage, firstPage)};
+ }
+ }
}
// If the info and the layout did not change and we already have
@@ -1461,8 +1474,12 @@
if (dashIndex > 0) {
fromIndex = Integer.parseInt(range.substring(0, dashIndex)) - 1;
- toIndex = Integer.parseInt(range.substring(
- dashIndex + 1, range.length())) - 1;
+ // It is possible that the dash is at the end since the input
+ // verification can has to allow the user to keep entering if
+ // this would lead to a valid input. So we handle this.
+ toIndex = (dashIndex < range.length() - 1)
+ ? Integer.parseInt(range.substring(dashIndex + 1,
+ range.length())) - 1 : fromIndex;
} else {
fromIndex = toIndex = Integer.parseInt(range) - 1;
}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 2257617..2be8ee5 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -292,11 +292,7 @@
c.drawRect(mFrame, mBatteryPaint);
c.restore();
- if (level <= EMPTY) {
- final float x = mWidth * 0.5f;
- final float y = (mHeight + mWarningTextHeight) * 0.48f;
- c.drawText(mWarningString, x, y, mWarningTextPaint);
- } else if (tracker.plugged) {
+ if (tracker.plugged) {
// draw the bolt
final int bl = (int)(mFrame.left + width / 4f);
final int bt = (int)(mFrame.top + height / 6f);
@@ -319,6 +315,10 @@
mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
}
c.drawPath(mBoltPath, mBoltPaint);
+ } else if (level <= EMPTY) {
+ final float x = mWidth * 0.5f;
+ final float y = (mHeight + mWarningTextHeight) * 0.48f;
+ c.drawText(mWarningString, x, y, mWarningTextPaint);
} else if (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
mTextPaint.setTextSize(height *
(SINGLE_DIGIT_PERCENT ? 0.75f
diff --git a/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
new file mode 100644
index 0000000..b4d3edd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 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.systemui.recent;
+
+import android.graphics.drawable.ColorDrawable;
+
+public class ColorDrawableWithDimensions extends ColorDrawable {
+ private int mWidth;
+ private int mHeight;
+
+ public ColorDrawableWithDimensions(int color, int width, int height) {
+ super(color);
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mHeight;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
rename to packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
index f17766b..1cfc892 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
@@ -30,7 +30,7 @@
import com.android.systemui.R;
-public class RecentsScrollViewPerformanceHelper {
+public class FadedEdgeDrawHelper {
public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
private View mScrollView;
@@ -43,18 +43,18 @@
private Matrix mFadeMatrix;
private LinearGradient mFade;
- public static RecentsScrollViewPerformanceHelper create(Context context,
+ public static FadedEdgeDrawHelper create(Context context,
AttributeSet attrs, View scrollView, boolean isVertical) {
boolean isTablet = context.getResources().
getBoolean(R.bool.config_recents_interface_for_tablets);
if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
- return new RecentsScrollViewPerformanceHelper(context, attrs, scrollView, isVertical);
+ return new FadedEdgeDrawHelper(context, attrs, scrollView, isVertical);
} else {
return null;
}
}
- public RecentsScrollViewPerformanceHelper(Context context,
+ public FadedEdgeDrawHelper(Context context,
AttributeSet attrs, View scrollView, boolean isVertical) {
mScrollView = scrollView;
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
@@ -64,7 +64,7 @@
}
public void onAttachedToWindowCallback(
- RecentsCallback callback, LinearLayout layout, boolean hardwareAccelerated) {
+ LinearLayout layout, boolean hardwareAccelerated) {
mSoftwareRendered = !hardwareAccelerated;
if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
|| USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
@@ -178,11 +178,11 @@
}
}
- public int getVerticalFadingEdgeLengthCallback() {
+ public int getVerticalFadingEdgeLength() {
return mFadingEdgeLength;
}
- public int getHorizontalFadingEdgeLengthCallback() {
+ public int getHorizontalFadingEdgeLength() {
return mFadingEdgeLength;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 8b2cd3f..c714d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -25,7 +25,7 @@
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
@@ -62,8 +62,8 @@
private Handler mHandler;
private int mIconDpi;
- private Bitmap mDefaultThumbnailBackground;
- private Bitmap mDefaultIconBackground;
+ private ColorDrawableWithDimensions mDefaultThumbnailBackground;
+ private ColorDrawableWithDimensions mDefaultIconBackground;
private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
private boolean mFirstScreenful;
@@ -100,7 +100,7 @@
// Render default icon (just a blank image)
int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
- mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+ mDefaultIconBackground = new ColorDrawableWithDimensions(0x00000000, iconSize, iconSize);
// Render the default thumbnail background
int thumbnailWidth =
@@ -110,9 +110,7 @@
int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
mDefaultThumbnailBackground =
- Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(mDefaultThumbnailBackground);
- c.drawColor(color);
+ new ColorDrawableWithDimensions(color, thumbnailWidth, thumbnailHeight);
}
public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) {
@@ -125,11 +123,11 @@
}
}
- public Bitmap getDefaultThumbnail() {
+ public Drawable getDefaultThumbnail() {
return mDefaultThumbnailBackground;
}
- public Bitmap getDefaultIcon() {
+ public Drawable getDefaultIcon() {
return mDefaultIconBackground;
}
@@ -199,7 +197,7 @@
+ td + ": " + thumbnail);
synchronized (td) {
if (thumbnail != null) {
- td.setThumbnail(thumbnail);
+ td.setThumbnail(new BitmapDrawable(mContext.getResources(), thumbnail));
} else {
td.setThumbnail(mDefaultThumbnailBackground);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index f51e34b..f5670e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -22,7 +22,10 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -68,7 +71,14 @@
}
} else {
- Bitmap first = firstTask.getThumbnail();
+ Bitmap first = null;
+ if (firstTask.getThumbnail() instanceof BitmapDrawable) {
+ first = ((BitmapDrawable) firstTask.getThumbnail()).getBitmap();
+ } else {
+ first = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ Drawable d = RecentTasksLoader.getInstance(mContext).getDefaultThumbnail();
+ d.draw(new Canvas(first));
+ }
final Resources res = mContext.getResources();
float thumbWidth = res
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 217b7fd..be42bc0 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -49,16 +49,17 @@
private RecentsCallback mCallback;
protected int mLastScrollPosition;
private SwipeHelper mSwipeHelper;
- private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+ private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
private HashSet<View> mRecycledViews;
private int mNumItemsInOneScreenful;
+ private Runnable mOnScrollListener;
public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
float densityScale = getResources().getDisplayMetrics().density;
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
- mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false);
+ mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false);
mRecycledViews = new HashSet<View>();
}
@@ -108,8 +109,8 @@
final View view = mAdapter.getView(i, old, mLinearLayout);
- if (mPerformanceHelper != null) {
- mPerformanceHelper.addViewCallback(view);
+ if (mFadedEdgeDrawHelper != null) {
+ mFadedEdgeDrawHelper.addViewCallback(view);
}
OnTouchListener noOpListener = new OnTouchListener() {
@@ -234,26 +235,10 @@
}
@Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
+ public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
+ if (mFadedEdgeDrawHelper != null) {
- if (mPerformanceHelper != null) {
- int paddingLeft = mPaddingLeft;
- final boolean offsetRequired = isPaddingOffsetRequired();
- if (offsetRequired) {
- paddingLeft += getLeftPaddingOffset();
- }
-
- int left = mScrollX + paddingLeft;
- int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
- int top = mScrollY + getFadeTop(offsetRequired);
- int bottom = top + getFadeHeight(offsetRequired);
-
- if (offsetRequired) {
- right += getRightPaddingOffset();
- bottom += getBottomPaddingOffset();
- }
- mPerformanceHelper.drawCallback(canvas,
+ mFadedEdgeDrawHelper.drawCallback(canvas,
left, right, top, bottom, mScrollX, mScrollY,
0, 0,
getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), mPaddingTop);
@@ -261,9 +246,21 @@
}
@Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ if (mOnScrollListener != null) {
+ mOnScrollListener.run();
+ }
+ }
+
+ public void setOnScrollListener(Runnable listener) {
+ mOnScrollListener = listener;
+ }
+
+ @Override
public int getVerticalFadingEdgeLength() {
- if (mPerformanceHelper != null) {
- return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+ if (mFadedEdgeDrawHelper != null) {
+ return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
} else {
return super.getVerticalFadingEdgeLength();
}
@@ -271,8 +268,8 @@
@Override
public int getHorizontalFadingEdgeLength() {
- if (mPerformanceHelper != null) {
- return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+ if (mFadedEdgeDrawHelper != null) {
+ return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
} else {
return super.getHorizontalFadingEdgeLength();
}
@@ -290,9 +287,8 @@
@Override
public void onAttachedToWindow() {
- if (mPerformanceHelper != null) {
- mPerformanceHelper.onAttachedToWindowCallback(
- mCallback, mLinearLayout, isHardwareAccelerated());
+ if (mFadedEdgeDrawHelper != null) {
+ mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 5ebd11e0..788e843 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -30,6 +30,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
@@ -74,7 +75,7 @@
private PopupMenu mPopup;
private View mRecentsScrim;
private View mRecentsNoApps;
- private ViewGroup mRecentsContainer;
+ private RecentsScrollView mRecentsContainer;
private boolean mShowing;
private boolean mWaitingToShow;
@@ -98,6 +99,8 @@
public void setCallback(RecentsCallback callback);
public void setMinSwipeAlpha(float minAlpha);
public View findViewForTask(int persistentTaskId);
+ public void drawFadedEdges(Canvas c, int left, int right, int top, int bottom);
+ public void setOnScrollListener(Runnable listener);
}
private final class OnLongClickDelegate implements View.OnLongClickListener {
@@ -113,7 +116,7 @@
/* package */ final static class ViewHolder {
View thumbnailView;
ImageView thumbnailViewImage;
- Bitmap thumbnailViewImageBitmap;
+ Drawable thumbnailViewDrawable;
ImageView iconView;
TextView labelView;
TextView descriptionView;
@@ -151,7 +154,7 @@
// the thumbnail later (if they both have the same dimensions)
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
- holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+ holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -227,7 +230,7 @@
public void recycleView(View v) {
ViewHolder holder = (ViewHolder) v.getTag();
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
- holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+ holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
holder.iconView.setVisibility(INVISIBLE);
holder.iconView.animate().cancel();
holder.labelView.setText(null);
@@ -270,13 +273,7 @@
}
public int numItemsInOneScreenful() {
- if (mRecentsContainer instanceof RecentsScrollView){
- RecentsScrollView scrollView
- = (RecentsScrollView) mRecentsContainer;
- return scrollView.numItemsInOneScreenful();
- } else {
- throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
- }
+ return mRecentsContainer.numItemsInOneScreenful();
}
private boolean pointInside(int x, int y, View v) {
@@ -288,7 +285,7 @@
}
public boolean isInContentArea(int x, int y) {
- return pointInside(x, y, mRecentsContainer);
+ return pointInside(x, y, (View) mRecentsContainer);
}
public void show(boolean show) {
@@ -436,16 +433,16 @@
protected void onFinishInflate() {
super.onFinishInflate();
- mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
+ mRecentsContainer = (RecentsScrollView) findViewById(R.id.recents_container);
+ mRecentsContainer.setOnScrollListener(new Runnable() {
+ public void run() {
+ // need to redraw the faded edges
+ invalidate();
+ }
+ });
mListAdapter = new TaskDescriptionAdapter(mContext);
- if (mRecentsContainer instanceof RecentsScrollView){
- RecentsScrollView scrollView
- = (RecentsScrollView) mRecentsContainer;
- scrollView.setAdapter(mListAdapter);
- scrollView.setCallback(this);
- } else {
- throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
- }
+ mRecentsContainer.setAdapter(mListAdapter);
+ mRecentsContainer.setCallback(this);
mRecentsScrim = findViewById(R.id.recents_bg_protect);
mRecentsNoApps = findViewById(R.id.recents_no_apps);
@@ -462,11 +459,7 @@
}
public void setMinSwipeAlpha(float minAlpha) {
- if (mRecentsContainer instanceof RecentsScrollView){
- RecentsScrollView scrollView
- = (RecentsScrollView) mRecentsContainer;
- scrollView.setMinSwipeAlpha(minAlpha);
- }
+ mRecentsContainer.setMinSwipeAlpha(minAlpha);
}
private void createCustomAnimations(LayoutTransition transitioner) {
@@ -488,23 +481,23 @@
}
}
- private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
+ private void updateThumbnail(ViewHolder h, Drawable thumbnail, boolean show, boolean anim) {
if (thumbnail != null) {
// Should remove the default image in the frame
// that this now covers, to improve scrolling speed.
// That can't be done until the anim is complete though.
- h.thumbnailViewImage.setImageBitmap(thumbnail);
+ h.thumbnailViewImage.setImageDrawable(thumbnail);
// scale the image to fill the full width of the ImageView. do this only if
// we haven't set a bitmap before, or if the bitmap size has changed
- if (h.thumbnailViewImageBitmap == null ||
- h.thumbnailViewImageBitmap.getWidth() != thumbnail.getWidth() ||
- h.thumbnailViewImageBitmap.getHeight() != thumbnail.getHeight()) {
+ if (h.thumbnailViewDrawable == null ||
+ h.thumbnailViewDrawable.getIntrinsicWidth() != thumbnail.getIntrinsicWidth() ||
+ h.thumbnailViewDrawable.getIntrinsicHeight() != thumbnail.getIntrinsicHeight()) {
if (mFitThumbnailToXY) {
h.thumbnailViewImage.setScaleType(ScaleType.FIT_XY);
} else {
Matrix scaleMatrix = new Matrix();
- float scale = mThumbnailWidth / (float) thumbnail.getWidth();
+ float scale = mThumbnailWidth / (float) thumbnail.getIntrinsicWidth();
scaleMatrix.setScale(scale, scale);
h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
h.thumbnailViewImage.setImageMatrix(scaleMatrix);
@@ -517,14 +510,14 @@
}
h.thumbnailView.setVisibility(View.VISIBLE);
}
- h.thumbnailViewImageBitmap = thumbnail;
+ h.thumbnailViewDrawable = thumbnail;
}
}
void onTaskThumbnailLoaded(TaskDescription td) {
synchronized (td) {
if (mRecentsContainer != null) {
- ViewGroup container = mRecentsContainer;
+ ViewGroup container = (ViewGroup) mRecentsContainer;
if (container instanceof RecentsScrollView) {
container = (ViewGroup) container.findViewById(
R.id.recents_linear_layout);
@@ -633,7 +626,7 @@
final int items = mRecentTaskDescriptions != null
? mRecentTaskDescriptions.size() : 0;
- mRecentsContainer.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
+ ((View) mRecentsContainer).setVisibility(items > 0 ? View.VISIBLE : View.GONE);
// Set description for accessibility
int numRecentApps = mRecentTaskDescriptions != null
@@ -650,33 +643,33 @@
}
public boolean simulateClick(int persistentTaskId) {
- if (mRecentsContainer instanceof RecentsScrollView){
- RecentsScrollView scrollView
- = (RecentsScrollView) mRecentsContainer;
- View v = scrollView.findViewForTask(persistentTaskId);
- if (v != null) {
- handleOnClick(v);
- return true;
- }
+ View v = mRecentsContainer.findViewForTask(persistentTaskId);
+ if (v != null) {
+ handleOnClick(v);
+ return true;
}
return false;
}
public void handleOnClick(View view) {
- ViewHolder holder = (ViewHolder)view.getTag();
+ ViewHolder holder = (ViewHolder) view.getTag();
TaskDescription ad = holder.taskDescription;
final Context context = view.getContext();
final ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
- Bitmap bm = holder.thumbnailViewImageBitmap;
- boolean usingDrawingCache;
- if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
- bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
- usingDrawingCache = false;
- } else {
+
+ Bitmap bm = null;
+ boolean usingDrawingCache = true;
+ if (holder.thumbnailViewDrawable instanceof BitmapDrawable) {
+ bm = ((BitmapDrawable) holder.thumbnailViewDrawable).getBitmap();
+ if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
+ bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
+ usingDrawingCache = false;
+ }
+ }
+ if (usingDrawingCache) {
holder.thumbnailViewImage.setDrawingCacheEnabled(true);
bm = holder.thumbnailViewImage.getDrawingCache();
- usingDrawingCache = true;
}
Bundle opts = (bm == null) ?
null :
@@ -771,7 +764,7 @@
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.recent_remove_item) {
- mRecentsContainer.removeViewInLayout(selectedView);
+ ((ViewGroup) mRecentsContainer).removeViewInLayout(selectedView);
} else if (item.getItemId() == R.id.recent_inspect_item) {
ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
if (viewHolder != null) {
@@ -795,4 +788,26 @@
});
popup.show();
}
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+
+ int paddingLeft = mPaddingLeft;
+ final boolean offsetRequired = isPaddingOffsetRequired();
+ if (offsetRequired) {
+ paddingLeft += getLeftPaddingOffset();
+ }
+
+ int left = mScrollX + paddingLeft;
+ int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
+ int top = mScrollY + getFadeTop(offsetRequired);
+ int bottom = top + getFadeHeight(offsetRequired);
+
+ if (offsetRequired) {
+ right += getRightPaddingOffset();
+ bottom += getBottomPaddingOffset();
+ }
+ mRecentsContainer.drawFadedEdges(canvas, left, right, top, bottom);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index ee076d9..6dddc39 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -49,9 +49,10 @@
private RecentsCallback mCallback;
protected int mLastScrollPosition;
private SwipeHelper mSwipeHelper;
- private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+ private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
private HashSet<View> mRecycledViews;
private int mNumItemsInOneScreenful;
+ private Runnable mOnScrollListener;
public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
@@ -59,7 +60,7 @@
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
- mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true);
+ mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, true);
mRecycledViews = new HashSet<View>();
}
@@ -112,8 +113,8 @@
}
final View view = mAdapter.getView(i, old, mLinearLayout);
- if (mPerformanceHelper != null) {
- mPerformanceHelper.addViewCallback(view);
+ if (mFadedEdgeDrawHelper != null) {
+ mFadedEdgeDrawHelper.addViewCallback(view);
}
OnTouchListener noOpListener = new OnTouchListener() {
@@ -243,36 +244,32 @@
}
@Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
-
- if (mPerformanceHelper != null) {
- int paddingLeft = mPaddingLeft;
+ public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
+ if (mFadedEdgeDrawHelper != null) {
final boolean offsetRequired = isPaddingOffsetRequired();
- if (offsetRequired) {
- paddingLeft += getLeftPaddingOffset();
- }
-
- int left = mScrollX + paddingLeft;
- int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
- int top = mScrollY + getFadeTop(offsetRequired);
- int bottom = top + getFadeHeight(offsetRequired);
-
- if (offsetRequired) {
- right += getRightPaddingOffset();
- bottom += getBottomPaddingOffset();
- }
- mPerformanceHelper.drawCallback(canvas,
- left, right, top, bottom, mScrollX, mScrollY,
+ mFadedEdgeDrawHelper.drawCallback(canvas,
+ left, right, top + getFadeTop(offsetRequired), bottom, mScrollX, mScrollY,
getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
0, 0, mPaddingTop);
}
}
@Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ if (mOnScrollListener != null) {
+ mOnScrollListener.run();
+ }
+ }
+
+ public void setOnScrollListener(Runnable listener) {
+ mOnScrollListener = listener;
+ }
+
+ @Override
public int getVerticalFadingEdgeLength() {
- if (mPerformanceHelper != null) {
- return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+ if (mFadedEdgeDrawHelper != null) {
+ return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
} else {
return super.getVerticalFadingEdgeLength();
}
@@ -280,8 +277,8 @@
@Override
public int getHorizontalFadingEdgeLength() {
- if (mPerformanceHelper != null) {
- return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+ if (mFadedEdgeDrawHelper != null) {
+ return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
} else {
return super.getHorizontalFadingEdgeLength();
}
@@ -299,9 +296,8 @@
@Override
public void onAttachedToWindow() {
- if (mPerformanceHelper != null) {
- mPerformanceHelper.onAttachedToWindowCallback(
- mCallback, mLinearLayout, isHardwareAccelerated());
+ if (mFadedEdgeDrawHelper != null) {
+ mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
index 7e979b7..2bc2821 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
@@ -29,7 +29,7 @@
final String packageName; // used to override animations (see onClick())
final CharSequence description;
- private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
+ private Drawable mThumbnail; // generated by Activity.onCreateThumbnail()
private Drawable mIcon; // application package icon
private CharSequence mLabel; // application package label
private boolean mLoaded;
@@ -85,11 +85,11 @@
mIcon = icon;
}
- public void setThumbnail(Bitmap thumbnail) {
+ public void setThumbnail(Drawable thumbnail) {
mThumbnail = thumbnail;
}
- public Bitmap getThumbnail() {
+ public Drawable getThumbnail() {
return mThumbnail;
}
}
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
index 4bf1db8..596435a 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
@@ -25,6 +25,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
@@ -198,9 +199,15 @@
while (mIsRunning) {
try {
- ProxyConnection parser = new ProxyConnection(serverSocket.accept());
+ Socket socket = serverSocket.accept();
+ // Only receive local connections.
+ if (socket.getInetAddress().isLoopbackAddress()) {
+ ProxyConnection parser = new ProxyConnection(socket);
- threadExecutor.execute(parser);
+ threadExecutor.execute(parser);
+ } else {
+ socket.close();
+ }
} catch (IOException e) {
e.printStackTrace();
}
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index c6c4a94..67b2307 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -113,7 +113,7 @@
uid = _uid;
packageName = _packageName;
op = _op;
- mode = AppOpsManager.MODE_ALLOWED;
+ mode = AppOpsManager.opToDefaultMode(op);
}
}
@@ -191,7 +191,7 @@
mHandler = new Handler();
readState();
}
-
+
public void publish(Context context) {
mContext = context;
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
@@ -379,7 +379,7 @@
}
repCbs.addAll(cbs);
}
- if (mode == AppOpsManager.MODE_ALLOWED) {
+ if (mode == AppOpsManager.opToDefaultMode(op.op)) {
// If going into the default mode, prune this op
// if there is nothing else interesting in it.
pruneOp(op, uid, packageName);
@@ -435,8 +435,8 @@
Ops pkgOps = ent.getValue();
for (int j=pkgOps.size()-1; j>=0; j--) {
Op curOp = pkgOps.valueAt(j);
- if (curOp.mode != AppOpsManager.MODE_ALLOWED) {
- curOp.mode = AppOpsManager.MODE_ALLOWED;
+ if (curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
+ curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
changed = true;
callbacks = addCallbacks(callbacks, packageName, curOp.op,
mOpModeWatchers.get(curOp.op));
@@ -545,7 +545,7 @@
synchronized (this) {
Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
if (op == null) {
- return AppOpsManager.MODE_ALLOWED;
+ return AppOpsManager.opToDefaultMode(code);
}
return op.mode;
}
@@ -947,7 +947,7 @@
AppOpsManager.OpEntry op = ops.get(j);
out.startTag(null, "op");
out.attribute(null, "n", Integer.toString(op.getOp()));
- if (op.getMode() != AppOpsManager.MODE_ALLOWED) {
+ if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
out.attribute(null, "m", Integer.toString(op.getMode()));
}
long time = op.getTime();
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 37fbb13..fea7623 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -143,6 +143,7 @@
* Information about services for a single user.
*/
class ServiceMap extends Handler {
+ final int mUserId;
final ArrayMap<ComponentName, ServiceRecord> mServicesByName
= new ArrayMap<ComponentName, ServiceRecord>();
final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent
@@ -165,6 +166,10 @@
static final int MSG_BG_START_TIMEOUT = 1;
+ ServiceMap(int userId) {
+ mUserId = userId;
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -224,6 +229,9 @@
Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
sendMessageAtTime(msg, when);
}
+ if (mStartingBackground.size() < mMaxStartingBackground) {
+ mAm.backgroundServicesFinishedLocked(mUserId);
+ }
}
}
@@ -239,10 +247,15 @@
return getServiceMap(callingUser).mServicesByName.get(name);
}
+ boolean hasBackgroundServices(int callingUser) {
+ ServiceMap smap = mServiceMap.get(callingUser);
+ return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false;
+ }
+
private ServiceMap getServiceMap(int callingUser) {
ServiceMap smap = mServiceMap.get(callingUser);
if (smap == null) {
- smap = new ServiceMap();
+ smap = new ServiceMap(callingUser);
mServiceMap.put(callingUser, smap);
}
return smap;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2bac96e..676b330 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1903,8 +1903,8 @@
private ActivityManagerService() {
Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
- mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT);
- mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT);
+ mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT, false);
+ mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT, true);
mBroadcastQueues[0] = mFgBroadcastQueue;
mBroadcastQueues[1] = mBgBroadcastQueue;
@@ -4910,6 +4910,7 @@
final int userId = mStartedUsers.keyAt(i);
Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
broadcastIntentLocked(null, null, intent, null,
new IIntentReceiver.Stub() {
@Override
@@ -4924,7 +4925,7 @@
},
0, null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
- AppOpsManager.OP_NONE, false, false, MY_PID, Process.SYSTEM_UID,
+ AppOpsManager.OP_NONE, true, false, MY_PID, Process.SYSTEM_UID,
userId);
}
}
@@ -12578,14 +12579,13 @@
boolean doTrim = false;
synchronized(this) {
- ReceiverList rl
- = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
+ ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl != null) {
if (rl.curBroadcast != null) {
BroadcastRecord r = rl.curBroadcast;
final boolean doNext = finishReceiverLocked(
receiver.asBinder(), r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort);
if (doNext) {
doTrim = true;
r.queue.processNextBroadcast(false);
@@ -13212,16 +13212,20 @@
}
private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
- String resultData, Bundle resultExtras, boolean resultAbort,
- boolean explicit) {
+ String resultData, Bundle resultExtras, boolean resultAbort) {
final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver);
if (r == null) {
Slog.w(TAG, "finishReceiver called but not found on queue");
return false;
}
- return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort,
- explicit);
+ return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, false);
+ }
+
+ void backgroundServicesFinishedLocked(int userId) {
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ queue.backgroundServicesFinishedLocked(userId);
+ }
}
public void finishReceiver(IBinder who, int resultCode, String resultData,
@@ -13236,7 +13240,7 @@
final long origId = Binder.clearCallingIdentity();
try {
boolean doNext = false;
- BroadcastRecord r = null;
+ BroadcastRecord r;
synchronized(this) {
r = broadcastRecordForReceiverLocked(who);
@@ -14749,7 +14753,7 @@
}
private final void setProcessTrackerState(ProcessRecord proc, int memFactor, long now) {
- if (proc.thread != null) {
+ if (proc.thread != null && proc.baseProcessTracker != null) {
proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
}
}
@@ -15704,10 +15708,11 @@
final int userId = uss.mHandle.getIdentifier();
Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
- false, false, MY_PID, Process.SYSTEM_UID, userId);
+ true, false, MY_PID, Process.SYSTEM_UID, userId);
}
int num = mUserLru.size();
int i = 0;
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 6e50808..4359895 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -143,9 +143,6 @@
private boolean inHistory; // are we in the history stack?
final ActivityStackSupervisor mStackSupervisor;
- /** Launch the home activity rather than the activity at the top of stack */
- boolean mLaunchHomeTaskNext;
-
void dump(PrintWriter pw, String prefix) {
final long now = SystemClock.uptimeMillis();
pw.print(prefix); pw.print("packageName="); pw.print(packageName);
@@ -243,6 +240,8 @@
pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
pw.print(" forceNewConfig="); pw.println(forceNewConfig);
+ pw.print(prefix); pw.print("mActivityType=");
+ pw.println(activityTypeToString(mActivityType));
pw.print(prefix); pw.print("thumbHolder: ");
pw.print(Integer.toHexString(System.identityHashCode(thumbHolder)));
if (thumbHolder != null) {
@@ -1040,6 +1039,15 @@
return null;
}
+ private String activityTypeToString(int type) {
+ switch (type) {
+ case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
+ case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
+ case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE";
+ default: return Integer.toString(type);
+ }
+ }
+
@Override
public String toString() {
if (stringName != null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 064b3a8..c31c213 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1000,7 +1000,8 @@
boolean behindFullscreen = !mStackSupervisor.isFrontStack(this) &&
!(forceHomeShown && isHomeStack());
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
- final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+ final TaskRecord task = mTaskHistory.get(taskNdx);
+ final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.finishing) {
@@ -1083,7 +1084,7 @@
// At this point, nothing else needs to be shown
if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
behindFullscreen = true;
- } else if (r.mLaunchHomeTaskNext) {
+ } else if (task.mOnTopOfHome) {
if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
showHomeBehindStack = true;
behindFullscreen = true;
@@ -1224,7 +1225,7 @@
final TaskRecord nextTask = next.task;
final TaskRecord prevTask = prev != null ? prev.task : null;
- if (prevTask != null && prev.mLaunchHomeTaskNext && prev.finishing && prev.frontOfTask) {
+ if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
if (prevTask == nextTask) {
ArrayList<ActivityRecord> activities = prevTask.mActivities;
@@ -1234,7 +1235,6 @@
// r is usually the same as next, but what if two activities were launched
// before prev finished?
if (!r.finishing) {
- r.mLaunchHomeTaskNext = true;
r.frontOfTask = true;
break;
}
@@ -1243,7 +1243,7 @@
// This task is going away but it was supposed to return to the home task.
// Now the task above it has to return to the home task instead.
final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
- mTaskHistory.get(taskNdx).mActivities.get(0).mLaunchHomeTaskNext = true;
+ mTaskHistory.get(taskNdx).mOnTopOfHome = true;
} else {
if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Launching home next");
return mStackSupervisor.resumeHomeActivity(prev);
@@ -1843,16 +1843,17 @@
// bottom of the activity stack. This also keeps it
// correctly ordered with any activities we previously
// moved.
- TaskRecord bottomTask = mTaskHistory.get(0);
- ActivityRecord p = bottomTask.mActivities.get(0);
- if (target.taskAffinity != null
- && target.taskAffinity.equals(p.task.affinity)) {
+ final ActivityRecord bottom =
+ !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
+ mTaskHistory.get(0).mActivities.get(0) : null;
+ if (bottom != null && target.taskAffinity != null
+ && target.taskAffinity.equals(bottom.task.affinity)) {
// If the activity currently at the bottom has the
// same task affinity as the one we are moving,
// then merge it into the same task.
- target.setTask(p.task, p.thumbHolder, false);
+ target.setTask(bottom.task, bottom.thumbHolder, false);
if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
- + " out to bottom task " + p.task);
+ + " out to bottom task " + bottom.task);
} else {
target.setTask(createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
null, false), null, false);
@@ -1868,7 +1869,7 @@
boolean noOptions = canMoveOptions;
final int start = replyChainEnd < 0 ? i : replyChainEnd;
for (int srcPos = start; srcPos >= i; --srcPos) {
- p = activities.get(srcPos);
+ final ActivityRecord p = activities.get(srcPos);
if (p.finishing) {
continue;
}
@@ -2932,7 +2933,7 @@
if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
// Caller wants the home activity moved with it. To accomplish this,
// we'll just indicate that this task returns to the home task.
- task.mActivities.get(0).mLaunchHomeTaskNext = true;
+ task.mOnTopOfHome = true;
}
moveTaskToFrontLocked(task, null, options);
return true;
@@ -2993,17 +2994,17 @@
* If a watcher is installed, the action is preflighted and the watcher has an opportunity
* to premeptively cancel the move.
*
- * @param task The taskId to collect and move to the bottom.
+ * @param taskId The taskId to collect and move to the bottom.
* @return Returns true if the move completed, false if not.
*/
- final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
- Slog.i(TAG, "moveTaskToBack: " + task);
+ final boolean moveTaskToBackLocked(int taskId, ActivityRecord reason) {
+ Slog.i(TAG, "moveTaskToBack: " + taskId);
// If we have a watcher, preflight the move before committing to it. First check
// for *other* available tasks, but if none are available, then try again allowing the
// current task to be selected.
if (mStackSupervisor.isFrontStack(this) && mService.mController != null) {
- ActivityRecord next = topRunningActivityLocked(null, task);
+ ActivityRecord next = topRunningActivityLocked(null, taskId);
if (next == null) {
next = topRunningActivityLocked(null, 0);
}
@@ -3023,9 +3024,9 @@
}
if (DEBUG_TRANSITION) Slog.v(TAG,
- "Prepare to back transition: task=" + task);
+ "Prepare to back transition: task=" + taskId);
- final TaskRecord tr = taskForIdLocked(task);
+ final TaskRecord tr = taskForIdLocked(taskId);
if (tr == null) {
return false;
}
@@ -3037,28 +3038,15 @@
// We make sure here that some activity in the stack will launch home.
ActivityRecord lastActivity = null;
int numTasks = mTaskHistory.size();
- int taskNdx;
- for (taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
- final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
- int activityNdx;
- for (activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.mLaunchHomeTaskNext) {
- break;
- }
- if (taskNdx == 1 && activityNdx == 0) {
- // Final activity before tr task.
- lastActivity = r;
- }
- }
- if (activityNdx >= 0) {
- // Early exit, we found an activity that will launchHomeTaskNext.
+ for (int taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
+ final TaskRecord task = mTaskHistory.get(taskNdx);
+ if (task.mOnTopOfHome) {
break;
}
- }
- if (lastActivity != null) {
- // No early exit, we did not find an activity that will launchHomeTaskNext, set one.
- lastActivity.mLaunchHomeTaskNext = true;
+ if (taskNdx == 1) {
+ // Set the last task before tr to go to home.
+ task.mOnTopOfHome = true;
+ }
}
if (reason != null &&
@@ -3071,15 +3059,15 @@
} else {
mWindowManager.prepareAppTransition(AppTransition.TRANSIT_TASK_TO_BACK, false);
}
- mWindowManager.moveTaskToBottom(task);
+ mWindowManager.moveTaskToBottom(taskId);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
- if (numTasks <= 1 || (mResumedActivity != null && mResumedActivity.task == tr &&
- mResumedActivity.mLaunchHomeTaskNext)) {
- mResumedActivity.mLaunchHomeTaskNext = false;
+ final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
+ if (task == tr && task.mOnTopOfHome || numTasks <= 1) {
+ task.mOnTopOfHome = false;
return mStackSupervisor.resumeHomeActivity(null);
}
@@ -3426,7 +3414,7 @@
}
final ActivityRecord top = topRunningActivityLocked(null);
final boolean launchHomeTaskNext =
- top != null && top.app == app && top.mLaunchHomeTaskNext;
+ top != null && top.app == app && top.task.mOnTopOfHome;
// Remove this application's activities from active lists.
boolean hasVisibleActivities = removeHistoryRecordsForAppLocked(app);
@@ -3533,6 +3521,11 @@
}
boolean removeTask(TaskRecord task) {
+ final int taskNdx = mTaskHistory.indexOf(task);
+ final int topTaskNdx = mTaskHistory.size() - 1;
+ if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
+ mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
+ }
mTaskHistory.remove(task);
return mTaskHistory.isEmpty();
}
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index f5d45b3..8ad29f3 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -282,7 +282,7 @@
boolean resumeHomeActivity(ActivityRecord prev) {
moveHomeStack(true);
if (prev != null) {
- prev.mLaunchHomeTaskNext = false;
+ prev.task.mOnTopOfHome = false;
}
mHomeStack.moveHomeTaskToTop();
ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
@@ -304,7 +304,7 @@
r = stack.topRunningActivityLocked(null);
}
if (r != null && !r.isHomeActivity() && r.isRootActivity()) {
- r.mLaunchHomeTaskNext = true;
+ r.task.mOnTopOfHome = true;
}
}
}
@@ -1417,8 +1417,8 @@
final ActivityStack lastStack = getLastStack();
ActivityRecord curTop = lastStack == null?
null : lastStack.topRunningNonDelayedActivityLocked(notTop);
- if (curTop != null && (curTop.task != intentActivity.task) ||
- curTop.task != lastStack.topTask()) {
+ if (curTop != null && (curTop.task != intentActivity.task ||
+ curTop.task != lastStack.topTask())) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (sourceRecord == null || (sourceStack.topActivity() != null &&
sourceStack.topActivity().task == sourceRecord.task)) {
@@ -1429,7 +1429,7 @@
(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
// Caller wants to appear on home activity.
- r.mLaunchHomeTaskNext = true;
+ intentActivity.task.mOnTopOfHome = true;
}
targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
options = null;
@@ -1543,7 +1543,7 @@
// sure we have correctly resumed the top activity.
if (doResume) {
// Reset flag so it gets correctly reevaluated.
- intentActivity.mLaunchHomeTaskNext = false;
+ intentActivity.task.mOnTopOfHome = false;
setLaunchHomeTaskNextFlag(sourceRecord, intentActivity, targetStack);
targetStack.resumeTopActivityLocked(null, options);
} else {
@@ -1640,7 +1640,7 @@
== (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
// Caller wants to appear on home activity, so before starting
// their own activity we will bring home to the front.
- r.mLaunchHomeTaskNext = true;
+ r.task.mOnTopOfHome = true;
}
}
} else if (sourceRecord != null) {
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 254a219..b35ca79 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -54,8 +54,9 @@
static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
- static final int MAX_BROADCAST_HISTORY = 25;
- static final int MAX_BROADCAST_SUMMARY_HISTORY = 100;
+ static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 25;
+ static final int MAX_BROADCAST_SUMMARY_HISTORY
+ = ActivityManager.isLowRamDeviceStatic() ? 25 : 100;
final ActivityManagerService mService;
@@ -70,14 +71,20 @@
final long mTimeoutPeriod;
/**
+ * If true, we can delay broadcasts while waiting services to finish in the previous
+ * receiver's process.
+ */
+ final boolean mDelayBehindServices;
+
+ /**
* Lists of all active broadcasts that are to be executed immediately
* (without waiting for another broadcast to finish). Currently this only
* contains broadcasts to registered receivers, to avoid spinning up
* a bunch of processes to execute IntentReceiver components. Background-
* and foreground-priority broadcasts are queued separately.
*/
- final ArrayList<BroadcastRecord> mParallelBroadcasts
- = new ArrayList<BroadcastRecord>();
+ final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>();
+
/**
* List of all active broadcasts that are to be executed one at a time.
* The object at the top of the list is the currently activity broadcasts;
@@ -85,20 +92,17 @@
* broadcasts, separate background- and foreground-priority queues are
* maintained.
*/
- final ArrayList<BroadcastRecord> mOrderedBroadcasts
- = new ArrayList<BroadcastRecord>();
+ final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>();
/**
* Historical data of past broadcasts, for debugging.
*/
- final BroadcastRecord[] mBroadcastHistory
- = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+ final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
/**
* Summary of historical data of past broadcasts, for debugging.
*/
- final Intent[] mBroadcastSummaryHistory
- = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
+ final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
/**
* Set when we current have a BROADCAST_INTENT_MSG in flight.
@@ -128,10 +132,6 @@
static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
final Handler mHandler = new Handler() {
- //public Handler() {
- // if (localLOGV) Slog.v(TAG, "Handler started!");
- //}
-
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
@@ -163,10 +163,12 @@
}
}
- BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod) {
+ BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod,
+ boolean allowDelayBehindServices) {
mService = service;
mQueueName = name;
mTimeoutPeriod = timeoutPeriod;
+ mDelayBehindServices = allowDelayBehindServices;
}
public boolean isPendingBroadcastProcessLocked(int pid) {
@@ -260,7 +262,7 @@
+ br.curComponent.flattenToShortString(), e);
logBroadcastReceiverDiscardLocked(br);
finishReceiverLocked(br, br.resultCode, br.resultData,
- br.resultExtras, br.resultAbort, true);
+ br.resultExtras, br.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
br.state = BroadcastRecord.IDLE;
@@ -289,7 +291,7 @@
// let the broadcast continue.
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort, false);
reschedule = true;
}
@@ -299,7 +301,7 @@
"[" + mQueueName + "] skip & discard pending app " + r);
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort, false);
reschedule = true;
}
if (reschedule) {
@@ -330,14 +332,11 @@
}
public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
- String resultData, Bundle resultExtras, boolean resultAbort,
- boolean explicit) {
- int state = r.state;
+ String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
+ final int state = r.state;
r.state = BroadcastRecord.IDLE;
if (state == BroadcastRecord.IDLE) {
- if (explicit) {
- Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
- }
+ Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
}
r.receiver = null;
r.intent.setComponent(null);
@@ -348,15 +347,35 @@
r.curFilter.receiverList.curBroadcast = null;
}
r.curFilter = null;
- r.curApp = null;
- r.curComponent = null;
r.curReceiver = null;
+ r.curApp = null;
mPendingBroadcast = null;
r.resultCode = resultCode;
r.resultData = resultData;
r.resultExtras = resultExtras;
- r.resultAbort = resultAbort;
+ if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
+ r.resultAbort = resultAbort;
+ } else {
+ r.resultAbort = false;
+ }
+
+ if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
+ && r.queue.mOrderedBroadcasts.size() > 0
+ && r.queue.mOrderedBroadcasts.get(0) == r) {
+ // In this case, we are ready to process the next receiver for the current broadcast,
+ // but are on a queue that would like to wait for services to finish before moving
+ // on. If there are background services currently starting, then we will go into a
+ // special state where we hold off on continuing this broadcast until they are done.
+ if (mService.mServices.hasBackgroundServices(r.userId)) {
+ Slog.i(ActivityManagerService.TAG, "Delay finish: "
+ + r.curComponent.flattenToShortString());
+ r.state = BroadcastRecord.WAITING_SERVICES;
+ return false;
+ }
+ }
+
+ r.curComponent = null;
// We will process the next receiver right now if this is finishing
// an app receiver (which is always asynchronous) or after we have
@@ -365,6 +384,18 @@
|| state == BroadcastRecord.CALL_DONE_RECEIVE;
}
+ public void backgroundServicesFinishedLocked(int userId) {
+ if (mOrderedBroadcasts.size() > 0) {
+ BroadcastRecord br = mOrderedBroadcasts.get(0);
+ if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
+ Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast");
+ br.curComponent = null;
+ br.state = BroadcastRecord.IDLE;
+ processNextBroadcast(false);
+ }
+ }
+ }
+
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
@@ -821,7 +852,7 @@
// sent the broadcast.
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
r.state = BroadcastRecord.IDLE;
@@ -850,7 +881,7 @@
+ r.intent + ": process is bad");
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
@@ -917,7 +948,21 @@
}
}
- Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+ BroadcastRecord br = mOrderedBroadcasts.get(0);
+ if (br.state == BroadcastRecord.WAITING_SERVICES) {
+ // In this case the broadcast had already finished, but we had decided to wait
+ // for started services to finish as well before going on. So if we have actually
+ // waited long enough time timeout the broadcast, let's give up on the whole thing
+ // and just move on to the next.
+ Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null
+ ? br.curComponent.flattenToShortString() : "(null)"));
+ br.curComponent = null;
+ br.state = BroadcastRecord.IDLE;
+ processNextBroadcast(false);
+ return;
+ }
+
+ Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r. receiver
+ ", started " + (now - r.receiverTime) + "ms ago");
r.receiverTime = now;
r.anrCount++;
@@ -957,7 +1002,7 @@
// Move on to the next receiver.
finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
if (anrMessage != null) {
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index db61e88..b2cfd7a 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -70,6 +70,7 @@
static final int APP_RECEIVE = 1;
static final int CALL_IN_RECEIVE = 2;
static final int CALL_DONE_RECEIVE = 3;
+ static final int WAITING_SERVICES = 4;
// The following are set when we are calling a receiver (one that
// was found in our list of registered receivers).
@@ -153,6 +154,7 @@
case APP_RECEIVE: stateStr=" (APP_RECEIVE)"; break;
case CALL_IN_RECEIVE: stateStr=" (CALL_IN_RECEIVE)"; break;
case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
+ case WAITING_SERVICES: stateStr=" (WAITING_SERVICES)"; break;
}
pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 4fdacb3..7a456f7 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -407,9 +407,9 @@
}
public void makeInactive(ProcessStatsService tracker) {
- if (thread != null) {
- thread = null;
- final ProcessStats.ProcessState origBase = baseProcessTracker;
+ thread = null;
+ final ProcessStats.ProcessState origBase = baseProcessTracker;
+ if (origBase != null) {
if (origBase != null) {
origBase.setState(ProcessStats.STATE_NOTHING,
tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
@@ -567,7 +567,16 @@
*/
public boolean addPackage(String pkg, ProcessStatsService tracker) {
if (!pkgList.containsKey(pkg)) {
- pkgList.put(pkg, tracker.getProcessStateLocked(pkg, info.uid, processName));
+ if (baseProcessTracker != null) {
+ ProcessStats.ProcessState state = tracker.getProcessStateLocked(
+ pkg, info.uid, processName);
+ pkgList.put(pkg, state);
+ if (state != baseProcessTracker) {
+ state.makeActive();
+ }
+ } else {
+ pkgList.put(pkg, null);
+ }
return true;
}
return false;
@@ -592,25 +601,30 @@
* Delete all packages from list except the package indicated in info
*/
public void resetPackageList(ProcessStatsService tracker) {
- long now = SystemClock.uptimeMillis();
- baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), now, pkgList);
final int N = pkgList.size();
- if (N != 1) {
- for (int i=0; i<N; i++) {
- ProcessStats.ProcessState ps = pkgList.valueAt(i);
- if (ps != null && ps != baseProcessTracker) {
- ps.makeInactive();
- }
+ if (baseProcessTracker != null) {
+ long now = SystemClock.uptimeMillis();
+ baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), now, pkgList);
+ if (N != 1) {
+ for (int i=0; i<N; i++) {
+ ProcessStats.ProcessState ps = pkgList.valueAt(i);
+ if (ps != null && ps != baseProcessTracker) {
+ ps.makeInactive();
+ }
+ }
+ pkgList.clear();
+ ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
+ info.packageName, info.uid, processName);
+ pkgList.put(info.packageName, ps);
+ if (ps != baseProcessTracker) {
+ ps.makeActive();
+ }
}
+ } else if (N != 1) {
pkgList.clear();
- ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
- info.packageName, info.uid, processName);
- pkgList.put(info.packageName, ps);
- if (thread != null && ps != baseProcessTracker) {
- ps.makeActive();
- }
+ pkgList.put(info.packageName, null);
}
}
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index 582e11e..0a1685c 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -30,6 +30,7 @@
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TimeUtils;
import com.android.internal.app.IProcessStats;
import com.android.internal.app.ProcessStats;
import com.android.internal.os.BackgroundThread;
@@ -39,6 +40,7 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -313,7 +315,8 @@
return true;
}
- private ArrayList<String> getCommittedFiles(int minNum, boolean inclAll) {
+ private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent,
+ boolean inclCheckedIn) {
File[] files = mBaseDir.listFiles();
if (files == null || files.length <= minNum) {
return null;
@@ -325,11 +328,11 @@
File file = files[i];
String fileStr = file.getPath();
if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
- if (!inclAll && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
+ if (!inclCheckedIn && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
continue;
}
- if (fileStr.equals(currentFile)) {
+ if (!inclCurrent && fileStr.equals(currentFile)) {
if (DEBUG) Slog.d(TAG, "Skipping: current stats");
continue;
}
@@ -340,7 +343,7 @@
}
public void trimHistoricStatesWriteLocked() {
- ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, true);
+ ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true);
if (filesArray == null) {
return;
}
@@ -409,6 +412,8 @@
}
public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
+ mAm.mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.PACKAGE_USAGE_STATS, null);
Parcel current = Parcel.obtain();
mWriteLock.lock();
try {
@@ -417,7 +422,7 @@
mProcessStats.writeToParcel(current, 0);
}
if (historic != null) {
- ArrayList<String> files = getCommittedFiles(0, true);
+ ArrayList<String> files = getCommittedFiles(0, false, true);
if (files != null) {
for (int i=files.size()-1; i>=0; i--) {
try {
@@ -436,6 +441,76 @@
return current.marshall();
}
+ public ParcelFileDescriptor getStatsOverTime(long minTime) {
+ mAm.mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+ mWriteLock.lock();
+ try {
+ Parcel current = Parcel.obtain();
+ long curTime;
+ synchronized (mAm) {
+ mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+ mProcessStats.writeToParcel(current, 0);
+ curTime = mProcessStats.mTimePeriodEndRealtime
+ - mProcessStats.mTimePeriodStartRealtime;
+ }
+ if (curTime < minTime) {
+ // Need to add in older stats to reach desired time.
+ ArrayList<String> files = getCommittedFiles(0, false, true);
+ if (files.size() > 0) {
+ current.setDataPosition(0);
+ ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
+ current.recycle();
+ int i = 0;
+ while (i < files.size() && (stats.mTimePeriodEndRealtime
+ - stats.mTimePeriodStartRealtime) < minTime) {
+ AtomicFile file = new AtomicFile(new File(files.get(i)));
+ i++;
+ ProcessStats moreStats = new ProcessStats(false);
+ readLocked(moreStats, file);
+ if (moreStats.mReadError == null) {
+ stats.add(moreStats);
+ StringBuilder sb = new StringBuilder();
+ sb.append("Added stats: ");
+ sb.append(moreStats.mTimePeriodStartClockStr);
+ sb.append(", over ");
+ TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime
+ - moreStats.mTimePeriodStartRealtime, sb);
+ Slog.i(TAG, sb.toString());
+ } else {
+ Slog.w(TAG, "Failure reading " + files.get(i) + "; "
+ + moreStats.mReadError);
+ continue;
+ }
+ }
+ current = Parcel.obtain();
+ stats.writeToParcel(current, 0);
+ }
+ }
+ final byte[] outData = current.marshall();
+ current.recycle();
+ final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+ Thread thr = new Thread("ProcessStats pipe output") {
+ public void run() {
+ FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
+ try {
+ fout.write(outData);
+ fout.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failure writing pipe", e);
+ }
+ }
+ };
+ thr.start();
+ return fds[0];
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed building output pipe", e);
+ } finally {
+ mWriteLock.unlock();
+ }
+ return null;
+ }
+
public int getCurrentMemoryState() {
synchronized (mAm) {
return mLastMemOnlyState;
@@ -445,7 +520,8 @@
static private void dumpHelp(PrintWriter pw) {
pw.println("Process stats (procstats) dump options:");
pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
- pw.println(" [--details] [--current] [--commit] [--reset] [--write] [-h] [<package.name>]");
+ pw.println(" [--details] [--full-details] [--current] [--one-day]");
+ pw.println(" [--commit] [--reset] [--clear] [--write] [-h] [<package.name>]");
pw.println(" --checkin: perform a checkin: print and delete old committed states.");
pw.println(" --c: print only state in checkin format.");
pw.println(" --csv: output data suitable for putting in a spreadsheet.");
@@ -454,9 +530,12 @@
pw.println(" --csv-proc: pers, top, fore, vis, precept, backup,");
pw.println(" service, home, prev, cached");
pw.println(" --details: dump all execution details, not just summary.");
+ pw.println(" --full-details: dump only detail information, for all saved state.");
pw.println(" --current: only dump current state.");
+ pw.println(" --one-day: dump stats aggregated across about one day.");
pw.println(" --commit: commit current stats to disk and reset to start new stats.");
pw.println(" --reset: reset current stats, without committing.");
+ pw.println(" --clear: clear all stats; does both --reset and deletes old stats.");
pw.println(" --write: write current in-memory stats to disk.");
pw.println(" --read: replace current stats with last-written stats.");
pw.println(" -a: print everything.");
@@ -481,7 +560,9 @@
boolean isCsv = false;
boolean currentOnly = false;
boolean dumpDetails = false;
+ boolean dumpFullDetails = false;
boolean dumpAll = false;
+ boolean oneDay = false;
String reqPackage = null;
boolean csvSepScreenStats = false;
int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON};
@@ -549,6 +630,10 @@
csvSepProcStats = sep[0];
} else if ("--details".equals(arg)) {
dumpDetails = true;
+ } else if ("--full-details".equals(arg)) {
+ dumpFullDetails = true;
+ } else if ("--one-day".equals(arg)) {
+ oneDay = true;
} else if ("--current".equals(arg)) {
currentOnly = true;
} else if ("--commit".equals(arg)) {
@@ -564,6 +649,18 @@
pw.println("Process stats reset.");
}
return;
+ } else if ("--clear".equals(arg)) {
+ synchronized (mAm) {
+ mProcessStats.resetSafely();
+ ArrayList<String> files = getCommittedFiles(0, true, true);
+ if (files != null) {
+ for (int fi=0; fi<files.size(); fi++) {
+ (new File(files.get(fi))).delete();
+ }
+ }
+ pw.println("All process stats cleared.");
+ }
+ return;
} else if ("--write".equals(arg)) {
synchronized (mAm) {
writeStateSyncLocked();
@@ -653,13 +750,36 @@
*/
}
return;
+ } else if (oneDay) {
+ ParcelFileDescriptor pfd = getStatsOverTime(24*60*60*1000);
+ if (pfd == null) {
+ pw.println("Unable to build stats!");
+ return;
+ }
+ ProcessStats stats = new ProcessStats(false);
+ InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ stats.read(stream);
+ if (stats.mReadError != null) {
+ pw.print("Failure reading: "); pw.println(stats.mReadError);
+ return;
+ }
+ if (isCompact) {
+ stats.dumpCheckinLocked(pw, reqPackage);
+ } else {
+ if (dumpDetails || dumpFullDetails) {
+ stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll);
+ } else {
+ stats.dumpSummaryLocked(pw, reqPackage, now);
+ }
+ }
+ return;
}
boolean sepNeeded = false;
if (!currentOnly || isCheckin) {
mWriteLock.lock();
try {
- ArrayList<String> files = getCommittedFiles(0, !isCheckin);
+ ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
if (files != null) {
for (int i=0; i<files.size(); i++) {
if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
@@ -693,7 +813,11 @@
// Don't really need to lock because we uniquely own this object.
// Always dump summary here, dumping all details is just too
// much crud.
- processStats.dumpSummaryLocked(pw, reqPackage, now);
+ if (dumpFullDetails) {
+ mProcessStats.dumpLocked(pw, reqPackage, now, false, false);
+ } else {
+ processStats.dumpSummaryLocked(pw, reqPackage, now);
+ }
}
if (isCheckin) {
// Rename file suffix to mark that it has checked in.
@@ -719,8 +843,8 @@
pw.println();
pw.println("CURRENT STATS:");
}
- if (dumpDetails) {
- mProcessStats.dumpLocked(pw, reqPackage, now, dumpAll);
+ if (dumpDetails || dumpFullDetails) {
+ mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll);
if (dumpAll) {
pw.print(" mFile="); pw.println(mFile.getBaseFile());
}
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 479665c..f0bba4f 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -60,6 +60,9 @@
/** Takes on same set of values as ActivityRecord.mActivityType */
private int mTaskType;
+ /** Launch the home activity when leaving this task. */
+ boolean mOnTopOfHome = false;
+
TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
taskId = _taskId;
affinity = info.taskAffinity;
@@ -411,11 +414,12 @@
}
void dump(PrintWriter pw, String prefix) {
- if (numActivities != 0 || rootWasReset || userId != 0) {
+ if (numActivities != 0 || rootWasReset || userId != 0 || numFullscreen != 0) {
pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
pw.print(" rootWasReset="); pw.print(rootWasReset);
pw.print(" userId="); pw.print(userId);
- pw.print(" numFullscreen="); pw.println(numFullscreen);
+ pw.print(" numFullscreen="); pw.print(numFullscreen);
+ pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome);
}
if (affinity != null) {
pw.print(prefix); pw.print("affinity="); pw.println(affinity);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index dbd42af..69ff449 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -923,7 +923,8 @@
//that was created later or a window at the top of the list of
//windows associated with this token.
if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
- "Adding window " + win + " at " + (newIdx + 1) + " of " + N);
+ "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of " +
+ N);
windows.add(newIdx + 1, win);
if (newIdx < 0) {
// No window from token found on win's display.
@@ -1044,7 +1045,7 @@
}
}
if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
- "Adding window " + win + " at " + i + " of " + N);
+ "Based on layer: Adding window " + win + " at " + i + " of " + N);
windows.add(i, win);
mWindowsChanged = true;
return tokenWindowsPos;
@@ -1063,7 +1064,7 @@
}
i++;
if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
- "Adding window " + win + " at " + i + " of " + windows.size());
+ "Free window: Adding window " + win + " at " + i + " of " + windows.size());
windows.add(i, win);
mWindowsChanged = true;
}
@@ -1130,6 +1131,8 @@
}
private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
+ if (DEBUG_FOCUS_LIGHT) Slog.d(TAG, "addWindowToListInOrderLocked: win=" + win +
+ " Callers=" + Debug.getCallers(4));
if (win.mAttachedWindow == null) {
final WindowToken token = win.mToken;
int tokenWindowsPos = 0;
@@ -1185,16 +1188,15 @@
// same display. Or even when the current IME/target are not on the same screen as the next
// IME/target. For now only look for input windows on the main screen.
WindowList windows = getDefaultWindowListLocked();
- final int N = windows.size();
WindowState w = null;
- int i = N;
- while (i > 0) {
- i--;
- w = windows.get(i);
+ int i;
+ for (i = windows.size() - 1; i >= 0; --i) {
+ WindowState win = windows.get(i);
if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG, "Checking window @" + i
- + " " + w + " fl=0x" + Integer.toHexString(w.mAttrs.flags));
- if (canBeImeTarget(w)) {
+ + " " + win + " fl=0x" + Integer.toHexString(win.mAttrs.flags));
+ if (canBeImeTarget(win)) {
+ w = win;
//Slog.i(TAG, "Putting input method here!");
// Yet more tricksyness! If this window is a "starting"
@@ -7081,19 +7083,17 @@
}
}
- if (lastFocus != newFocus) {
- //System.out.println("Changing focus from " + lastFocus
- // + " to " + newFocus);
- if (newFocus != null) {
- if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Gaining focus: " + newFocus);
- newFocus.reportFocusChangedSerialized(true, mInTouchMode);
- notifyFocusChanged();
- }
+ //System.out.println("Changing focus from " + lastFocus
+ // + " to " + newFocus);
+ if (newFocus != null) {
+ if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Gaining focus: " + newFocus);
+ newFocus.reportFocusChangedSerialized(true, mInTouchMode);
+ notifyFocusChanged();
+ }
- if (lastFocus != null) {
- if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing focus: " + lastFocus);
- lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
- }
+ if (lastFocus != null) {
+ if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing focus: " + lastFocus);
+ lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
}
} break;
@@ -10277,14 +10277,13 @@
void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
- int j = 0;
final int numDisplays = mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
final WindowState w = windowList.get(winNdx);
if (windows == null || windows.contains(w)) {
- pw.print(" Window #"); pw.print(j++); pw.print(' ');
+ pw.print(" Window #"); pw.print(winNdx); pw.print(' ');
pw.print(w); pw.println(":");
w.dump(pw, " ", dumpAll || windows != null);
}