Merge "Ensure the selection does not change in setTextAndKeepSelection." into froyo
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 52f767e..34648b5 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -5,7 +5,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- stagefright.cpp
+ stagefright.cpp \
+ SineSource.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libutils libbinder
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index fec9e1a..4405da6 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -20,9 +20,12 @@
#include <string.h>
#include <unistd.h>
+#include "SineSource.h"
+
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
+#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CachingDataSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/HTTPDataSource.h>
@@ -42,6 +45,7 @@
static long gMaxNumFrames; // 0 means decode all available.
static long gReproduceBug; // if not -1.
static bool gPreferSoftwareCodec;
+static bool gPlaybackAudio;
static int64_t getNowUs() {
struct timeval tv;
@@ -73,7 +77,20 @@
rawSource->start();
- if (gReproduceBug >= 3 && gReproduceBug <= 5) {
+ if (gPlaybackAudio) {
+ AudioPlayer *player = new AudioPlayer(NULL);
+ player->setSource(rawSource);
+
+ player->start(true /* sourceAlreadyStarted */);
+
+ status_t finalStatus;
+ while (!player->reachedEOS(&finalStatus)) {
+ usleep(100000ll);
+ }
+
+ delete player;
+ player = NULL;
+ } else if (gReproduceBug >= 3 && gReproduceBug <= 5) {
int64_t durationUs;
CHECK(meta->findInt64(kKeyDuration, &durationUs));
@@ -245,6 +262,7 @@
fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n");
fprintf(stderr, " -t(humbnail) extract video thumbnail or album art\n");
fprintf(stderr, " -s(oftware) prefer software codec\n");
+ fprintf(stderr, " -o playback audio\n");
}
int main(int argc, char **argv) {
@@ -258,9 +276,10 @@
gMaxNumFrames = 0;
gReproduceBug = -1;
gPreferSoftwareCodec = false;
+ gPlaybackAudio = false;
int res;
- while ((res = getopt(argc, argv, "han:lm:b:pts")) >= 0) {
+ while ((res = getopt(argc, argv, "han:lm:b:ptso")) >= 0) {
switch (res) {
case 'a':
{
@@ -314,6 +333,12 @@
break;
}
+ case 'o':
+ {
+ gPlaybackAudio = true;
+ break;
+ }
+
case '?':
case 'h':
default:
@@ -325,6 +350,11 @@
}
}
+ if (gPlaybackAudio && !audioOnly) {
+ // This doesn't make any sense if we're decoding the video track.
+ gPlaybackAudio = false;
+ }
+
argc -= optind;
argv += optind;
@@ -456,6 +486,11 @@
dataSource = new FileSource(filename);
}
+ if (dataSource == NULL) {
+ fprintf(stderr, "Unable to create data source.\n");
+ return 1;
+ }
+
bool isJPEG = false;
size_t len = strlen(filename);
@@ -467,10 +502,18 @@
if (isJPEG) {
mediaSource = new JPEGSource(dataSource);
+ } else if (!strncasecmp("sine:", filename, 5)) {
+ char *end;
+ long sampleRate = strtol(filename + 5, &end, 10);
+
+ if (end == filename + 5) {
+ sampleRate = 44100;
+ }
+ mediaSource = new SineSource(sampleRate, 1);
} else {
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
if (extractor == NULL) {
- fprintf(stderr, "could not create data source\n");
+ fprintf(stderr, "could not create extractor.\n");
return -1;
}
@@ -492,6 +535,17 @@
if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
break;
}
+
+ meta = NULL;
+ }
+
+ if (meta == NULL) {
+ fprintf(stderr,
+ "No suitable %s track found. The '-a' option will "
+ "target audio tracks only, the default is to target "
+ "video tracks only.\n",
+ audioOnly ? "audio" : "video");
+ return -1;
}
int64_t thumbTimeUs;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b3223e5..c9096cf 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -145,6 +145,13 @@
public static final int RECENT_WITH_EXCLUDED = 0x0001;
/**
+ * @hide
+ * TODO: Make this public. Provides a list that does not contain any
+ * recent tasks that currently are not available to the user.
+ */
+ public static final int RECENT_IGNORE_UNAVAILABLE = 0x0002;
+
+ /**
* Return a list of the tasks that the user has recently launched, with
* the most recent being first and older ones after in order.
*
diff --git a/core/java/android/app/backup/BackupAgentHelper.java b/core/java/android/app/backup/BackupAgentHelper.java
index 788b1b5..6d73090 100644
--- a/core/java/android/app/backup/BackupAgentHelper.java
+++ b/core/java/android/app/backup/BackupAgentHelper.java
@@ -21,16 +21,28 @@
import java.io.IOException;
/**
- * A convenient BackupAgent wrapper class that automatically manages
+ * A convenient {@link BackupAgent} wrapper class that automatically manages
* heterogeneous data sets within the backup data, each identified by a unique
- * key prefix. An application will typically extend this class in their own
- * backup agent. Then, within the agent's onBackup() and onRestore() methods, it
- * will call {@link #addHelper(String, BackupHelper)} one or more times to
- * specify the data sets, then invoke super.onBackup() or super.onRestore() to
- * have the BackupAgentHelper implementation process the data.
+ * key prefix. When processing a backup or restore operation, the BackupAgentHelper
+ * dispatches to one or more installed {@link BackupHelper helpers} objects, each
+ * of which is responsible for a defined subset of the data being processed.
* <p>
- * STOPSHIP: document!
+ * An application will typically extend this class in their own
+ * backup agent. Then, within the agent's {@link BackupAgent#onCreate() onCreate()}
+ * method, it will call {@link #addHelper(String, BackupHelper)} one or more times to
+ * install the handlers for each kind of data it wishes to manage within its backups.
+ * <p>
+ * The Android framework currently provides two predefined {@link BackupHelper} classes:
+ * {@link FileBackupHelper}, which manages the backup and restore of entire files
+ * within an application's data directory hierarchy; and {@link SharedPreferencesBackupHelper},
+ * which manages the backup and restore of an application's
+ * {@link android.content.SharedPreferences} data.
+ * <p>
+ * An application can also implement its own helper classes to work within the
+ * {@link BackupAgentHelper} framework. See the {@link BackupHelper} interface
+ * documentation for details.
*
+ * @see BackupHelper
* @see FileBackupHelper
* @see SharedPreferencesBackupHelper
*/
diff --git a/core/java/android/app/backup/BackupDataInputStream.java b/core/java/android/app/backup/BackupDataInputStream.java
index a7f4ba6..465b3b6 100644
--- a/core/java/android/app/backup/BackupDataInputStream.java
+++ b/core/java/android/app/backup/BackupDataInputStream.java
@@ -20,7 +20,21 @@
import java.io.IOException;
/**
- * STOPSHIP: document */
+ * Used by {@link BackupHelper} classes within the {@link BackupAgentHelper} mechanism,
+ * this class provides an {@link java.io.InputStream}-like interface for accessing an
+ * entity's data during a restore operation.
+ * <p>
+ * When {@link BackupHelper#restoreEntity(BackupDataInputStream) BackupHelper.restoreEntity(BackupDataInputStream)}
+ * is called, the current entity's header has already been read from the underlying
+ * {@link BackupDataInput}. The entity's key string and total data size are available
+ * through this class's {@link #getKey()} and {@link #size()} methods, respectively.
+ * <p class="note">
+ * <em>Note:</em> The caller should take care not to seek or close the underlying data
+ * source, or to read more than {@link #size()} bytes total from the stream.</p>
+ *
+ * @see BackupAgentHelper
+ * @see BackupHelper
+ */
public class BackupDataInputStream extends InputStream {
String key;
@@ -34,6 +48,13 @@
mData = data;
}
+ /**
+ * Read one byte of entity data from the stream, returning it as
+ * an integer value. If more than {@link #size()} bytes of data
+ * are read from the stream, the output of this method is undefined.
+ *
+ * @return The byte read, or undefined if the end of the stream has been reached.
+ */
public int read() throws IOException {
byte[] one = mOneByte;
if (mOneByte == null) {
@@ -43,18 +64,52 @@
return one[0];
}
+ /**
+ * Read up to {@code size} bytes of data into a byte array, beginning at position
+ * {@code offset} within the array.
+ *
+ * @param b Byte array into which the data will be read
+ * @param offset The data will be stored in {@code b} beginning at this index
+ * within the array.
+ * @param size The number of bytes to read in this operation. If insufficient
+ * data exists within the entity to fulfill this request, only as much data
+ * will be read as is available.
+ * @return The number of bytes of data read, or zero if all of the entity's
+ * data has already been read.
+ */
public int read(byte[] b, int offset, int size) throws IOException {
return mData.readEntityData(b, offset, size);
}
+ /**
+ * Read enough entity data into a byte array to fill the array.
+ *
+ * @param b Byte array to fill with data from the stream. If the stream does not
+ * have sufficient data to fill the array, then the contents of the remainder of
+ * the array will be undefined.
+ * @return The number of bytes of data read, or zero if all of the entity's
+ * data has already been read.
+ */
public int read(byte[] b) throws IOException {
return mData.readEntityData(b, 0, b.length);
}
+ /**
+ * Report the key string associated with this entity within the backup data set.
+ *
+ * @return The key string for this entity, equivalent to calling
+ * {@link BackupDataInput#getKey()} on the underlying {@link BackupDataInput}.
+ */
public String getKey() {
return this.key;
}
-
+
+ /**
+ * Report the total number of bytes of data available for the current entity.
+ *
+ * @return The number of data bytes available, equivalent to calling
+ * {@link BackupDataInput#getDataSize()} on the underlying {@link BackupDataInput}.
+ */
public int size() {
return this.dataSize;
}
diff --git a/core/java/android/app/backup/BackupHelper.java b/core/java/android/app/backup/BackupHelper.java
index 3f41ed2..87b581b 100644
--- a/core/java/android/app/backup/BackupHelper.java
+++ b/core/java/android/app/backup/BackupHelper.java
@@ -19,11 +19,21 @@
import android.os.ParcelFileDescriptor;
/**
- * A convenient interface to be used with the
- * {@link android.app.backup.BackupAgentHelper} class to implement backup and restore of
- * arbitrary data types.
+ * This interface defines the calling interface that {@link BackupAgentHelper} uses
+ * when dispatching backup and restore operations to the installed helpers.
+ * Applications can define and install their own helpers as well as using those
+ * provided as part of the Android framework.
* <p>
- * STOPSHIP: document!
+ * Although multiple helper objects may be installed simultaneously, each helper
+ * is responsible only for handling its own data, and will not see entities
+ * created by other components within the backup system. Invocations of multiple
+ * helpers are performed sequentially by the {@link BackupAgentHelper}, with each
+ * helper given a chance to access its own saved state from within the state record
+ * produced during the previous backup operation.
+ *
+ * @see BackupAgentHelper
+ * @see FileBackupHelper
+ * @see SharedPreferencesBackupHelper
*/
public interface BackupHelper {
/**
@@ -31,24 +41,46 @@
* application's data directory need to be backed up, write them to
* <code>data</code>, and fill in <code>newState</code> with the state as it
* exists now.
+ * <p>
+ * Implementing this method is much like implementing
+ * {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
+ * — the method parameters are the same. When this method is invoked the
+ * {@code oldState} descriptor points to the beginning of the state data
+ * written during this helper's previous backup operation, and the {@code newState}
+ * descriptor points to the file location at which the helper should write its
+ * new state after performing the backup operation.
+ * <p class="note">
+ * <em>Note:</em> The helper should not close or seek either the {@code oldState} or
+ * the {@code newState} file descriptors.</p>
*/
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState);
/**
* Called by {@link android.app.backup.BackupAgentHelper BackupAgentHelper}
- * to restore one entity from the restore dataset.
- * <p class=note>
- * Do not close the <code>data</code> stream. Do not read more than
- * <code>data.size()</code> bytes from <code>data</code>.
+ * to restore a single entity from the restore data set. This method will be
+ * called for each entity in the data set that belongs to this handler.
+ * <p class="note">
+ * <em>Note:</em> Do not close the <code>data</code> stream. Do not read more than
+ * <code>data.size()</code> bytes from <code>data</code>.</p>
*/
public void restoreEntity(BackupDataInputStream data);
/**
* Called by {@link android.app.backup.BackupAgentHelper BackupAgentHelper}
* after a restore operation to write the backup state file corresponding to
- * the data as processed by the helper.
+ * the data as processed by the helper. The data written here will be
+ * available to the helper during the next call to its
+ * {@link #performBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
+ * method.
+ * <p>
+ * Note that this method will be called even if the handler's
+ * {@link #restoreEntity(BackupDataInputStream)} method was never invoked during
+ * the restore operation.
+ * <p class="note">
+ * <em>Note:</em> The helper should not close or seek the {@code newState}
+ * file descriptor.</p>
*/
- public void writeNewStateDescription(ParcelFileDescriptor fd);
+ public void writeNewStateDescription(ParcelFileDescriptor newState);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e640005..e8c09b0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3306,13 +3306,13 @@
* The bandwidth throttle threshold (long)
* @hide
*/
- public static final String THROTTLE_THRESHOLD = "throttle_threshold";
+ public static final String THROTTLE_THRESHOLD_BYTES = "throttle_threshold_bytes";
/**
* The bandwidth throttle value (kbps)
* @hide
*/
- public static final String THROTTLE_VALUE = "throttle_value";
+ public static final String THROTTLE_VALUE_KBITSPS = "throttle_value_kbitsps";
/**
* The bandwidth throttle reset calendar day (1-28)
@@ -3327,12 +3327,6 @@
public static final String THROTTLE_NOTIFICATION_TYPE = "throttle_notification_type";
/**
- * The interface we throttle
- * @hide
- */
- public static final String THROTTLE_IFACE = "throttle_iface";
-
- /**
* Help URI for data throttling policy
* @hide
*/
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 906264a..7fd993a 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -102,8 +102,9 @@
com.android.internal.R.string.httpErrorBadUrl));
return false;
}
- // Make sure it is correctly URL encoded before sending the request
- if (!URLUtil.verifyURLEncoding(url)) {
+ // Make sure the host part of the url is correctly
+ // encoded before sending the request
+ if (!URLUtil.verifyURLEncoding(mListener.host())) {
mListener.error(EventHandler.ERROR_BAD_URL,
mListener.getContext().getString(
com.android.internal.R.string.httpErrorBadUrl));
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 12b8c74..e0f8bc0 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -476,6 +476,7 @@
}
WebViewWorker.CacheEncoding ce = new WebViewWorker.CacheEncoding();
ce.mEncoding = mEncoding;
+ ce.mListener = this;
WebViewWorker.getHandler().obtainMessage(
WebViewWorker.MSG_UPDATE_CACHE_ENCODING, ce).sendToTarget();
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4f2a67b..7bd83e7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2150,11 +2150,15 @@
mScrollX = pinLocX(Math.round(sx));
mScrollY = pinLocY(Math.round(sy));
+ // update webkit
if (oldX != mScrollX || oldY != mScrollY) {
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
+ } else {
+ // the scroll position is adjusted at the beginning of the
+ // zoom animation. But we want to update the WebKit at the
+ // end of the zoom animation. See comments in onScaleEnd().
+ sendOurVisibleRect();
}
-
- // update webkit
sendViewSizeZoom();
}
}
@@ -4655,13 +4659,16 @@
ted.mY = contentY;
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
- mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
if (mDeferTouchProcess) {
// still needs to set them for compute deltaX/Y
mLastTouchX = x;
mLastTouchY = y;
+ ted.mViewX = x;
+ ted.mViewY = y;
+ mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
break;
}
+ mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
if (!inFullScreenMode()) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(PREVENT_DEFAULT_TIMEOUT,
@@ -4687,17 +4694,20 @@
// pass the touch events from UI thread to WebCore thread
if (shouldForwardTouchEvent() && mConfirmMove && (firstMove
|| eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
+ mLastSentTouchTime = eventTime;
TouchEventData ted = new TouchEventData();
ted.mAction = action;
ted.mX = contentX;
ted.mY = contentY;
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
- mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
- mLastSentTouchTime = eventTime;
if (mDeferTouchProcess) {
+ ted.mViewX = x;
+ ted.mViewY = y;
+ mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
break;
}
+ mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
if (firstMove && !inFullScreenMode()) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(PREVENT_DEFAULT_TIMEOUT,
@@ -4862,6 +4872,10 @@
ted.mY = contentY;
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
+ if (mDeferTouchProcess) {
+ ted.mViewX = x;
+ ted.mViewY = y;
+ }
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
}
mLastTouchUpTime = eventTime;
@@ -4876,6 +4890,10 @@
ted.mY = contentY;
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
+ if (mDeferTouchProcess) {
+ ted.mViewX = x;
+ ted.mViewY = y;
+ }
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES){
doDoubleTap();
@@ -6152,6 +6170,10 @@
// simplicity for now, we don't set it.
ted.mMetaState = 0;
ted.mReprocess = mDeferTouchProcess;
+ if (mDeferTouchProcess) {
+ ted.mViewX = mLastTouchX;
+ ted.mViewY = mLastTouchY;
+ }
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES) {
mTouchMode = TOUCH_DONE_MODE;
@@ -6448,31 +6470,27 @@
TouchEventData ted = (TouchEventData) msg.obj;
switch (ted.mAction) {
case MotionEvent.ACTION_DOWN:
- mLastDeferTouchX = contentToViewX(ted.mX)
- - mScrollX;
- mLastDeferTouchY = contentToViewY(ted.mY)
- - mScrollY;
+ mLastDeferTouchX = ted.mViewX;
+ mLastDeferTouchY = ted.mViewY;
mDeferTouchMode = TOUCH_INIT_MODE;
break;
case MotionEvent.ACTION_MOVE: {
// no snapping in defer process
- int x = contentToViewX(ted.mX) - mScrollX;
- int y = contentToViewY(ted.mY) - mScrollY;
if (mDeferTouchMode != TOUCH_DRAG_MODE) {
mDeferTouchMode = TOUCH_DRAG_MODE;
- mLastDeferTouchX = x;
- mLastDeferTouchY = y;
+ mLastDeferTouchX = ted.mViewX;
+ mLastDeferTouchY = ted.mViewY;
startDrag();
}
int deltaX = pinLocX((int) (mScrollX
- + mLastDeferTouchX - x))
+ + mLastDeferTouchX - ted.mViewX))
- mScrollX;
int deltaY = pinLocY((int) (mScrollY
- + mLastDeferTouchY - y))
+ + mLastDeferTouchY - ted.mViewY))
- mScrollY;
doDrag(deltaX, deltaY);
- if (deltaX != 0) mLastDeferTouchX = x;
- if (deltaY != 0) mLastDeferTouchY = y;
+ if (deltaX != 0) mLastDeferTouchX = ted.mViewX;
+ if (deltaY != 0) mLastDeferTouchY = ted.mViewY;
break;
}
case MotionEvent.ACTION_UP:
@@ -6485,8 +6503,8 @@
break;
case WebViewCore.ACTION_DOUBLETAP:
// doDoubleTap() needs mLastTouchX/Y as anchor
- mLastTouchX = contentToViewX(ted.mX) - mScrollX;
- mLastTouchY = contentToViewY(ted.mY) - mScrollY;
+ mLastTouchX = ted.mViewX;
+ mLastTouchY = ted.mViewY;
doDoubleTap();
mDeferTouchMode = TOUCH_DONE_MODE;
break;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 625e7ba..0175aed 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -708,6 +708,8 @@
int mY;
int mMetaState;
boolean mReprocess;
+ float mViewX;
+ float mViewY;
}
static class GeolocationPermissionsData {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7ebbab0..64f05fe 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -290,4 +290,21 @@
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
<bool name="config_bluetooth_sco_off_call">true</bool>
+
+ <!-- The default data-use polling period. -->
+ <integer name="config_datause_polling_period_sec">600</integer>
+
+ <!-- The default data-use threshold in bytes. 0 disables-->
+ <integer name="config_datause_threshold_bytes">0</integer>
+
+ <!-- The default reduced-datarate value in kilobits per sec -->
+ <integer name="config_datause_throttle_kbitsps">300</integer>
+
+ <!-- The default iface on which to monitor data use -->
+ <string name="config_datause_iface">rmnet0</string>
+
+ <!-- The default reduced-datarate notification mask -->
+ <!-- 2 means give warning -->
+ <integer name="config_datause_notification_type">2</integer>
+
</resources>
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 005c64a..bcf2463 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -102,7 +102,7 @@
(numChannels == 2)
? AudioSystem::CHANNEL_OUT_STEREO
: AudioSystem::CHANNEL_OUT_MONO,
- 8192, 0, &AudioCallback, this, 0);
+ 0, 0, &AudioCallback, this, 0);
if ((err = mAudioTrack->initCheck()) != OK) {
delete mAudioTrack;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 0e21d08..323f145 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1642,6 +1642,8 @@
}
if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
+ || !memcmp(header, "ftyp3gr6", 8) || !memcmp(header, "ftyp3gs6", 8)
+ || !memcmp(header, "ftyp3ge6", 8) || !memcmp(header, "ftyp3gg6", 8)
|| !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
|| !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
|| !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index b9d6fbc..873c2aa 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -3040,7 +3040,7 @@
continue;
}
- OMXCodec::setComponentRole(omx, node, queryDecoders, mime);
+ OMXCodec::setComponentRole(omx, node, !queryDecoders, mime);
results->push();
CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 3908389..78f7b33 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -615,10 +615,27 @@
}
} break;
case UPDATED_MEDIA_STATUS: {
- try {
- PackageHelper.getMountService().finishMediaUpdate();
- } catch (RemoteException e) {
- Log.e(TAG, "MountService not running?");
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS");
+ boolean reportStatus = msg.arg1 == 1;
+ boolean doGc = msg.arg2 == 1;
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc);
+ if (doGc) {
+ // Force a gc to clear up stale containers.
+ Runtime.getRuntime().gc();
+ }
+ if (msg.obj != null) {
+ Set<SdInstallArgs> args = (Set<SdInstallArgs>) msg.obj;
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");
+ // Unload containers
+ unloadAllContainers(args);
+ }
+ if (reportStatus) {
+ try {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Invoking MountService call back");
+ PackageHelper.getMountService().finishMediaUpdate();
+ } catch (RemoteException e) {
+ Log.e(TAG, "MountService not running?");
+ }
}
} break;
case WRITE_SETTINGS: {
@@ -9429,9 +9446,9 @@
if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
mediaStatus+", mMediaMounted=" + mMediaMounted);
if (mediaStatus == mMediaMounted) {
- if (reportStatus) {
- mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
- }
+ Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+ reportStatus ? 1 : 0, -1);
+ mHandler.sendMessage(msg);
return;
}
mMediaMounted = mediaStatus;
@@ -9440,38 +9457,42 @@
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
- try {
- updateExternalMediaStatusInner(mediaStatus);
- } finally {
- if (reportStatus) {
- mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
- }
- }
+ updateExternalMediaStatusInner(mediaStatus, reportStatus);
}
});
}
- private void updateExternalMediaStatusInner(boolean mediaStatus) {
- // If we are up here that means there are packages to be
- // enabled or disabled.
+ /*
+ * Collect information of applications on external media, map them
+ * against existing containers and update information based on current
+ * mount status. Please note that we always have to report status
+ * if reportStatus has been set to true especially when unloading packages.
+ */
+ private void updateExternalMediaStatusInner(boolean mediaStatus,
+ boolean reportStatus) {
+ // Collection of uids
+ int uidArr[] = null;
+ // Collection of stale containers
+ HashSet<String> removeCids = new HashSet<String>();
+ // Collection of packages on external media with valid containers.
+ HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
+ // Get list of secure containers.
final String list[] = PackageHelper.getSecureContainerList();
if (list == null || list.length == 0) {
Log.i(TAG, "No secure containers on sdcard");
- return;
- }
-
- int uidList[] = new int[list.length];
- int num = 0;
- HashSet<String> removeCids = new HashSet<String>();
- HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
- synchronized (mPackages) {
- for (String cid : list) {
- SdInstallArgs args = new SdInstallArgs(cid);
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Processing container " + cid);
- boolean failed = true;
- try {
+ } else {
+ // Process list of secure containers and categorize them
+ // as active or stale based on their package internal state.
+ int uidList[] = new int[list.length];
+ int num = 0;
+ synchronized (mPackages) {
+ for (String cid : list) {
+ SdInstallArgs args = new SdInstallArgs(cid);
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Processing container " + cid);
String pkgName = args.getPackageName();
if (pkgName == null) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
+ removeCids.add(cid);
continue;
}
if (DEBUG_SD_INSTALL) Log.i(TAG, "Looking for pkg : " + pkgName);
@@ -9483,33 +9504,29 @@
" at code path: " + ps.codePathString);
// We do have a valid package installed on sdcard
processCids.put(args, ps.codePathString);
- failed = false;
int uid = ps.userId;
if (uid != -1) {
uidList[num++] = uid;
}
- }
- } finally {
- if (failed) {
+ } else {
// Stale container on sdcard. Just delete
if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
removeCids.add(cid);
}
}
}
- }
- // Organize uids
- int uidArr[] = null;
- if (num > 0) {
- // Sort uid list
- Arrays.sort(uidList, 0, num);
- // Throw away duplicates
- uidArr = new int[num];
- uidArr[0] = uidList[0];
- int di = 0;
- for (int i = 1; i < num; i++) {
- if (uidList[i-1] != uidList[i]) {
- uidArr[di++] = uidList[i];
+
+ if (num > 0) {
+ // Sort uid list
+ Arrays.sort(uidList, 0, num);
+ // Throw away duplicates
+ uidArr = new int[num];
+ uidArr[0] = uidList[0];
+ int di = 0;
+ for (int i = 1; i < num; i++) {
+ if (uidList[i-1] != uidList[i]) {
+ uidArr[di++] = uidList[i];
+ }
}
}
}
@@ -9520,7 +9537,7 @@
startCleaningPackages();
} else {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
- unloadMediaPackages(processCids, uidArr);
+ unloadMediaPackages(processCids, uidArr, reportStatus);
}
}
@@ -9545,10 +9562,7 @@
* Look at potentially valid container ids from processCids
* If package information doesn't match the one on record
* or package scanning fails, the cid is added to list of
- * removeCids and cleaned up. Since cleaning up containers
- * involves destroying them, we do not want any parse
- * references to such stale containers. So force gc's
- * to avoid unnecessary crashes.
+ * removeCids. We currently don't delete stale containers.
*/
private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids,
int uidArr[], HashSet<String> removeCids) {
@@ -9626,6 +9640,7 @@
if (pkgList.size() > 0) {
sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
}
+ // Force gc to avoid any stale parser references that we might have.
if (doGc) {
Runtime.getRuntime().gc();
}
@@ -9637,12 +9652,33 @@
}
}
+ /*
+ * Utility method to unload a list of specified containers
+ */
+ private void unloadAllContainers(Set<SdInstallArgs> cidArgs) {
+ // Just unmount all valid containers.
+ for (SdInstallArgs arg : cidArgs) {
+ synchronized (mInstallLock) {
+ arg.doPostDeleteLI(false);
+ }
+ }
+ }
+
+ /*
+ * Unload packages mounted on external media. This involves deleting
+ * package data from internal structures, sending broadcasts about
+ * diabled packages, gc'ing to free up references, unmounting all
+ * secure containers corresponding to packages on external media, and
+ * posting a UPDATED_MEDIA_STATUS message if status has been requested.
+ * Please note that we always have to post this message if status has
+ * been requested no matter what.
+ */
private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids,
- int uidArr[]) {
+ int uidArr[], final boolean reportStatus) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
ArrayList<String> pkgList = new ArrayList<String>();
ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
- Set<SdInstallArgs> keys = processCids.keySet();
+ final Set<SdInstallArgs> keys = processCids.keySet();
for (SdInstallArgs args : keys) {
String cid = args.cid;
String pkgName = args.getPackageName();
@@ -9660,22 +9696,23 @@
}
}
}
- // Send broadcasts
+ // We have to absolutely send UPDATED_MEDIA_STATUS only
+ // after confirming that all the receivers processed the ordered
+ // broadcast when packages get disabled, force a gc to clean things up.
+ // and unload all the containers.
if (pkgList.size() > 0) {
sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky) throws RemoteException {
- // Force gc now that everyone is done cleaning up, to release
- // references on assets.
- Runtime.getRuntime().gc();
+ Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+ reportStatus ? 1 : 0, 1, keys);
+ mHandler.sendMessage(msg);
}
});
- }
- // Just unmount all valid containers.
- for (SdInstallArgs args : keys) {
- synchronized (mInstallLock) {
- args.doPostDeleteLI(false);
- }
+ } else {
+ Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+ reportStatus ? 1 : 0, -1, keys);
+ mHandler.sendMessage(msg);
}
}
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 9d4e226..71557f5 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -66,23 +66,17 @@
private Context mContext;
- private int mPolicyPollPeriodSec;
- private static final int DEFAULT_POLLING_PERIOD_SEC = 60 * 10;
private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
-
private static final int TESTING_RESET_PERIOD_SEC = 60 * 3;
+ private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
private static final int PERIOD_COUNT = 6;
+ private int mPolicyPollPeriodSec;
private long mPolicyThreshold;
- // TODO - remove testing stuff?
- private static final long DEFAULT_TESTING_THRESHOLD = 1 * 1024 * 1024;
- private static final long DEFAULT_THRESHOLD = 0; // off by default
-
private int mPolicyThrottleValue;
- private static final int DEFAULT_THROTTLE_VALUE = 100; // 100 Kbps
-
private int mPolicyResetDay; // 1-28
+ private int mPolicyNotificationsAllowedMask;
private long mLastRead; // read byte count from last poll
private long mLastWrite; // write byte count from last poll
@@ -100,11 +94,10 @@
private DataRecorder mRecorder;
- private String mPolicyIface;
+ private String mIface;
private static final int NOTIFICATION_WARNING = 2;
private static final int NOTIFICATION_ALL = 0xFFFFFFFF;
- private int mPolicyNotificationsAllowedMask;
private Notification mThrottlingNotification;
private boolean mWarningNotificationSent = false;
@@ -146,16 +139,15 @@
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.THROTTLE_POLLING_SEC), false, this);
resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.THROTTLE_THRESHOLD), false, this);
+ Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.THROTTLE_VALUE), false, this);
+ Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.THROTTLE_RESET_DAY), false, this);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.THROTTLE_IFACE), false, this);
- // TODO - add help url
+ Settings.Secure.THROTTLE_HELP_URI), false, this);
}
@Override
@@ -172,18 +164,26 @@
public synchronized long getResetTime(String iface) {
enforceAccessPermission();
- if (iface.equals(mPolicyIface) && (mRecorder != null)) mRecorder.getPeriodEnd();
+ if ((iface != null) &&
+ iface.equals(mIface) &&
+ (mRecorder != null)) {
+ mRecorder.getPeriodEnd();
+ }
return 0;
}
public synchronized long getPeriodStartTime(String iface) {
enforceAccessPermission();
- if (iface.equals(mPolicyIface) && (mRecorder != null)) mRecorder.getPeriodStart();
+ if ((iface != null) &&
+ iface.equals(mIface) &&
+ (mRecorder != null)) {
+ mRecorder.getPeriodStart();
+ }
return 0;
}
//TODO - a better name? getCliffByteCountThreshold?
public synchronized long getCliffThreshold(String iface, int cliff) {
enforceAccessPermission();
- if ((cliff == 1) && iface.equals(mPolicyIface)) {
+ if ((iface != null) && (cliff == 1) && iface.equals(mIface)) {
return mPolicyThreshold;
}
return 0;
@@ -191,7 +191,7 @@
// TODO - a better name? getThrottleRate?
public synchronized int getCliffLevel(String iface, int cliff) {
enforceAccessPermission();
- if ((cliff == 1) && iface.equals(mPolicyIface)) {
+ if ((iface != null) && (cliff == 1) && iface.equals(mIface)) {
return mPolicyThrottleValue;
}
return 0;
@@ -205,7 +205,8 @@
public synchronized long getByteCount(String iface, int dir, int period, int ago) {
enforceAccessPermission();
- if (iface.equals(mPolicyIface) &&
+ if ((iface != null) &&
+ iface.equals(mIface) &&
(period == ThrottleManager.PERIOD_CYCLE) &&
(mRecorder != null)) {
if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
@@ -217,7 +218,7 @@
// TODO - a better name - getCurrentThrottleRate?
public synchronized int getThrottle(String iface) {
enforceAccessPermission();
- if (iface.equals(mPolicyIface) && (mThrottleIndex == 1)) {
+ if ((iface != null) && iface.equals(mIface) && (mThrottleIndex == 1)) {
return mPolicyThrottleValue;
}
return 0;
@@ -302,20 +303,27 @@
private void onPolicyChanged() {
boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
- int pollingPeriod = DEFAULT_POLLING_PERIOD_SEC;
- if (testing) pollingPeriod = TESTING_POLLING_PERIOD_SEC;
+ int pollingPeriod = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_datause_polling_period_sec);
mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
// TODO - remove testing stuff?
- long defaultThreshold = DEFAULT_THRESHOLD;
- if (testing) defaultThreshold = DEFAULT_TESTING_THRESHOLD;
+ long defaultThreshold = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_datause_threshold_bytes);
+ int defaultValue = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_datause_throttle_kbitsps);
synchronized (ThrottleService.this) {
mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(),
- Settings.Secure.THROTTLE_THRESHOLD, defaultThreshold);
+ Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
mPolicyThrottleValue = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.THROTTLE_VALUE, DEFAULT_THROTTLE_VALUE);
+ Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
+ if (testing) {
+ mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
+ mPolicyThreshold = TESTING_THRESHOLD;
+ }
}
+
mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.THROTTLE_RESET_DAY, -1);
if (mPolicyResetDay == -1 ||
@@ -325,15 +333,18 @@
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
}
+ mIface = mContext.getResources().getString(
+ com.android.internal.R.string.config_datause_iface);
synchronized (ThrottleService.this) {
- mPolicyIface = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.THROTTLE_IFACE);
- // TODO - read default from resource so it's device-specific
- if (mPolicyIface == null) mPolicyIface = "rmnet0";
+ if (mIface == null) {
+ mPolicyThreshold = 0;
+ }
}
+ int defaultNotificationType = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_datause_notification_type);
mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.THROTTLE_NOTIFICATION_TYPE, NOTIFICATION_ALL);
+ Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" + mPolicyPollPeriodSec +
", threshold=" + mPolicyThreshold + ", value=" + mPolicyThrottleValue +
@@ -352,8 +363,8 @@
long incRead = 0;
long incWrite = 0;
try {
- incRead = mNMService.getInterfaceRxCounter(mPolicyIface) - mLastRead;
- incWrite = mNMService.getInterfaceTxCounter(mPolicyIface) - mLastWrite;
+ incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
+ incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
} catch (RemoteException e) {
Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
}
@@ -383,11 +394,12 @@
broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, mRecorder.getPeriodEnd());
mContext.sendStickyBroadcast(broadcast);
+ mAlarmManager.cancel(mPendingPollIntent);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, next, mPendingPollIntent);
}
private void checkThrottleAndPostNotification(long currentTotal) {
- // are we even doing this?
+ // is throttling enabled?
if (mPolicyThreshold == 0)
return;
@@ -399,7 +411,7 @@
}
if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
try {
- mNMService.setInterfaceThrottle(mPolicyIface,
+ mNMService.setInterfaceThrottle(mIface,
mPolicyThrottleValue, mPolicyThrottleValue);
} catch (Exception e) {
Slog.e(TAG, "error setting Throttle: " + e);
@@ -463,7 +475,7 @@
private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Intent intent = new Intent();
// TODO - fix up intent
- intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
+ intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
@@ -492,7 +504,7 @@
mThrottleIndex = THROTTLE_INDEX_UNTHROTTLED;
}
try {
- mNMService.setInterfaceThrottle(mPolicyIface, -1, -1);
+ mNMService.setInterfaceThrottle(mIface, -1, -1);
} catch (Exception e) {
Slog.e(TAG, "error clearing Throttle: " + e);
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index cd6a131..657b6af 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -148,6 +148,7 @@
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean DEBUG_WALLPAPER = false;
+ static final boolean DEBUG_FREEZE = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
static final boolean MEASURE_LATENCY = false;
@@ -4418,7 +4419,8 @@
final int N = mWindows.size();
for (int i=0; i<N; i++) {
WindowState w = (WindowState)mWindows.get(i);
- if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
+ if (w.isVisibleLw() && !w.mObscured
+ && (w.mOrientationChanging || !w.isDrawnLw())) {
return;
}
}
@@ -7925,7 +7927,7 @@
final AppWindowToken atoken = mAppToken;
return mSurface != null && !mAttachedHidden
&& (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
- && !mDrawPending && !mCommitDrawPending
+ && (mOrientationChanging || (!mDrawPending && !mCommitDrawPending))
&& !mExiting && !mDestroying;
}
@@ -8029,12 +8031,14 @@
/**
* Returns true if the window has a surface that it has drawn a
- * complete UI in to.
+ * complete UI in to. Note that this returns true if the orientation
+ * is changing even if the window hasn't redrawn because we don't want
+ * to stop things from executing during that time.
*/
public boolean isDrawnLw() {
final AppWindowToken atoken = mAppToken;
return mSurface != null && !mDestroying
- && !mDrawPending && !mCommitDrawPending;
+ && (mOrientationChanging || (!mDrawPending && !mCommitDrawPending));
}
public boolean fillsScreenLw(int screenWidth, int screenHeight,
@@ -10291,6 +10295,12 @@
if (w.mAttachedHidden || !w.isReadyForDisplay()) {
if (!w.mLastHidden) {
//dump();
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Window hiding: waitingToShow="
+ + w.mRootToken.waitingToShow + " polvis="
+ + w.mPolicyVisibility + " atthid="
+ + w.mAttachedHidden + " tokhid="
+ + w.mRootToken.hidden + " vis="
+ + w.mViewVisibility);
w.mLastHidden = true;
if (SHOW_TRANSACTIONS) logSurface(w,
"HIDE (performLayout)", null);
@@ -10686,23 +10696,28 @@
} else if (animating) {
requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
}
- mQueue.setHoldScreenLocked(holdScreen != null);
- if (screenBrightness < 0 || screenBrightness > 1.0f) {
- mPowerManager.setScreenBrightnessOverride(-1);
- } else {
- mPowerManager.setScreenBrightnessOverride((int)
- (screenBrightness * Power.BRIGHTNESS_ON));
- }
- if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
- mPowerManager.setButtonBrightnessOverride(-1);
- } else {
- mPowerManager.setButtonBrightnessOverride((int)
- (buttonBrightness * Power.BRIGHTNESS_ON));
- }
- if (holdScreen != mHoldingScreenOn) {
- mHoldingScreenOn = holdScreen;
- Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
- mH.sendMessage(m);
+
+ if (DEBUG_FREEZE) Slog.v(TAG, "Layout: mDisplayFrozen=" + mDisplayFrozen
+ + " holdScreen=" + holdScreen);
+ if (!mDisplayFrozen) {
+ mQueue.setHoldScreenLocked(holdScreen != null);
+ if (screenBrightness < 0 || screenBrightness > 1.0f) {
+ mPowerManager.setScreenBrightnessOverride(-1);
+ } else {
+ mPowerManager.setScreenBrightnessOverride((int)
+ (screenBrightness * Power.BRIGHTNESS_ON));
+ }
+ if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
+ mPowerManager.setButtonBrightnessOverride(-1);
+ } else {
+ mPowerManager.setButtonBrightnessOverride((int)
+ (buttonBrightness * Power.BRIGHTNESS_ON));
+ }
+ if (holdScreen != mHoldingScreenOn) {
+ mHoldingScreenOn = holdScreen;
+ Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
+ mH.sendMessage(m);
+ }
}
if (mTurnOnScreen) {
@@ -10979,6 +10994,8 @@
mFreezeGcPending = now;
}
+ if (DEBUG_FREEZE) Slog.v(TAG, "*** FREEZING DISPLAY", new RuntimeException());
+
mDisplayFrozen = true;
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
@@ -11002,6 +11019,8 @@
return;
}
+ if (DEBUG_FREEZE) Slog.v(TAG, "*** UNFREEZING DISPLAY", new RuntimeException());
+
mDisplayFrozen = false;
mH.removeMessages(H.APP_FREEZE_TIMEOUT);
if (PROFILE_ORIENTATION) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index bc26fa0..b6f323d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6867,6 +6867,8 @@
enforceCallingPermission(android.Manifest.permission.GET_TASKS,
"getRecentTasks()");
+ IPackageManager pm = ActivityThread.getPackageManager();
+
final int N = mRecentTasks.size();
ArrayList<ActivityManager.RecentTaskInfo> res
= new ArrayList<ActivityManager.RecentTaskInfo>(
@@ -6883,6 +6885,25 @@
rti.baseIntent = new Intent(
tr.intent != null ? tr.intent : tr.affinityIntent);
rti.origActivity = tr.origActivity;
+
+ if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0) {
+ // Check whether this activity is currently available.
+ try {
+ if (rti.origActivity != null) {
+ if (pm.getActivityInfo(rti.origActivity, 0) == null) {
+ continue;
+ }
+ } else if (rti.baseIntent != null) {
+ if (pm.queryIntentActivities(rti.baseIntent,
+ null, 0) == null) {
+ continue;
+ }
+ }
+ } catch (RemoteException e) {
+ // Will never happen.
+ }
+ }
+
res.add(rti);
maxNum--;
}