diff options
88 files changed, 1226 insertions, 847 deletions
diff --git a/api/current.xml b/api/current.xml index 8651c4d7e6e9..760e5e05c4ac 100644 --- a/api/current.xml +++ b/api/current.xml @@ -76944,11 +76944,11 @@ visibility="public" > </field> -<field name="FOCUS_MODE_CONTINUOUS" +<field name="FOCUS_MODE_CONTINUOUS_VIDEO" type="java.lang.String" transient="false" volatile="false" - value=""continuous"" + value=""continuous-video"" static="true" final="true" deprecated="not deprecated" @@ -82537,8 +82537,8 @@ <exception name="IOException" type="java.io.IOException"> </exception> </method> -<method name="isImplemented" - return="java.lang.Boolean" +<method name="isPresent" + return="boolean" abstract="false" native="false" synchronized="false" @@ -82549,75 +82549,6 @@ > </method> </class> -<class name="GeocoderParams" - extends="java.lang.Object" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<implements name="android.os.Parcelable"> -</implements> -<method name="describeContents" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="getClientPackage" - return="java.lang.String" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="getLocale" - return="java.util.Locale" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="writeToParcel" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="parcel" type="android.os.Parcel"> -</parameter> -<parameter name="flags" type="int"> -</parameter> -</method> -<field name="CREATOR" - type="android.os.Parcelable.Creator" - transient="false" - volatile="false" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> <class name="GpsSatellite" extends="java.lang.Object" abstract="false" @@ -84209,396 +84140,6 @@ </field> </class> </package> -<package name="android.location.provider" -> -<class name="GeocodeProvider" - extends="java.lang.Object" - abstract="true" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="GeocodeProvider" - type="android.location.provider.GeocodeProvider" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<method name="getBinder" - return="android.os.IBinder" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onGetFromLocation" - return="java.lang.String" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="latitude" type="double"> -</parameter> -<parameter name="longitude" type="double"> -</parameter> -<parameter name="maxResults" type="int"> -</parameter> -<parameter name="params" type="android.location.GeocoderParams"> -</parameter> -<parameter name="addrs" type="java.util.List<android.location.Address>"> -</parameter> -</method> -<method name="onGetFromLocationName" - return="java.lang.String" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="locationName" type="java.lang.String"> -</parameter> -<parameter name="lowerLeftLatitude" type="double"> -</parameter> -<parameter name="lowerLeftLongitude" type="double"> -</parameter> -<parameter name="upperRightLatitude" type="double"> -</parameter> -<parameter name="upperRightLongitude" type="double"> -</parameter> -<parameter name="maxResults" type="int"> -</parameter> -<parameter name="params" type="android.location.GeocoderParams"> -</parameter> -<parameter name="addrs" type="java.util.List<android.location.Address>"> -</parameter> -</method> -</class> -<class name="LocationProvider" - extends="java.lang.Object" - abstract="true" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="LocationProvider" - type="android.location.provider.LocationProvider" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<method name="getBinder" - return="android.os.IBinder" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onAddListener" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="uid" type="int"> -</parameter> -<parameter name="ws" type="android.os.WorkSource"> -</parameter> -</method> -<method name="onDisable" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onEnable" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onEnableLocationTracking" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="enable" type="boolean"> -</parameter> -</method> -<method name="onGetAccuracy" - return="int" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onGetInternalState" - return="java.lang.String" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onGetPowerRequirement" - return="int" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onGetStatus" - return="int" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="extras" type="android.os.Bundle"> -</parameter> -</method> -<method name="onGetStatusUpdateTime" - return="long" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onHasMonetaryCost" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onMeetsCriteria" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="criteria" type="android.location.Criteria"> -</parameter> -</method> -<method name="onRemoveListener" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="uid" type="int"> -</parameter> -<parameter name="ws" type="android.os.WorkSource"> -</parameter> -</method> -<method name="onRequiresCell" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onRequiresNetwork" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onRequiresSatellite" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onSendExtraCommand" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="command" type="java.lang.String"> -</parameter> -<parameter name="extras" type="android.os.Bundle"> -</parameter> -</method> -<method name="onSetMinTime" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="minTime" type="long"> -</parameter> -<parameter name="ws" type="android.os.WorkSource"> -</parameter> -</method> -<method name="onSupportsAltitude" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onSupportsBearing" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onSupportsSpeed" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onUpdateLocation" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="location" type="android.location.Location"> -</parameter> -</method> -<method name="onUpdateNetworkState" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="state" type="int"> -</parameter> -<parameter name="info" type="android.net.NetworkInfo"> -</parameter> -</method> -<method name="reportLocation" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="location" type="android.location.Location"> -</parameter> -</method> -</class> -</package> <package name="android.media" > <class name="AsyncPlayer" @@ -85188,6 +84729,39 @@ <parameter name="value" type="short"> </parameter> </method> +<field name="ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="ALREADY_EXISTS" type="int" transient="false" @@ -85199,6 +84773,50 @@ visibility="public" > </field> +<field name="CONTENT_TYPE_GAME" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONTENT_TYPE_MOVIE" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONTENT_TYPE_MUSIC" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONTENT_TYPE_VOICE" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="EFFECT_AUXILIARY" type="java.lang.String" transient="false" @@ -85347,6 +84965,39 @@ visibility="public" > </field> +<field name="EXTRA_AUDIO_SESSION" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.extra.AUDIO_SESSION"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_CONTENT_TYPE" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.extra.CONTENT_TYPE"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_PACKAGE_NAME" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.extra.PACKAGE_NAME"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="NATIVE_EVENT_CONTROL_STATUS" type="int" transient="false" @@ -96356,6 +96007,17 @@ visibility="public" > </field> +<field name="ERROR_FILE_ALREADY_EXISTS" + type="int" + transient="false" + volatile="false" + value="1009" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="ERROR_FILE_ERROR" type="int" transient="false" @@ -96630,6 +96292,19 @@ <parameter name="value" type="java.lang.String"> </parameter> </method> +<method name="setShowRunningNotification" + return="android.net.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="show" type="boolean"> +</parameter> +</method> <method name="setTitle" return="android.net.DownloadManager.Request" abstract="false" diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp index c4242817bf4e..b7182991eaea 100644 --- a/cmds/stagefright/record.cpp +++ b/cmds/stagefright/record.cpp @@ -36,24 +36,30 @@ static const int32_t kFramerate = 24; // fps static const int32_t kIFramesIntervalSec = 1; static const int32_t kVideoBitRate = 512 * 1024; static const int32_t kAudioBitRate = 12200; -static const int32_t kColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; static const int64_t kDurationUs = 10000000LL; // 10 seconds #if 1 class DummySource : public MediaSource { public: - DummySource(int width, int height) + DummySource(int width, int height, int colorFormat) : mWidth(width), mHeight(height), + mColorFormat(colorFormat), mSize((width * height * 3) / 2) { mGroup.add_buffer(new MediaBuffer(mSize)); + + // Check the color format to make sure + // that the buffer size mSize it set correctly above. + CHECK(colorFormat == OMX_COLOR_FormatYUV420SemiPlanar || + colorFormat == OMX_COLOR_FormatYUV420Planar); } virtual sp<MetaData> getFormat() { sp<MetaData> meta = new MetaData; meta->setInt32(kKeyWidth, mWidth); meta->setInt32(kKeyHeight, mHeight); + meta->setInt32(kKeyColorFormat, mColorFormat); meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); return meta; @@ -100,6 +106,7 @@ protected: private: MediaBufferGroup mGroup; int mWidth, mHeight; + int mColorFormat; size_t mSize; int64_t mNumFramesOutput;; @@ -139,20 +146,47 @@ sp<MediaSource> createSource(const char *filename) { return source; } +enum { + kYUV420SP = 0, + kYUV420P = 1, +}; + +// returns -1 if mapping of the given color is unsuccessful +// returns an omx color enum value otherwise +static int translateColorToOmxEnumValue(int color) { + switch (color) { + case kYUV420SP: + return OMX_COLOR_FormatYUV420SemiPlanar; + case kYUV420P: + return OMX_COLOR_FormatYUV420Planar; + default: + fprintf(stderr, "Unsupported color: %d\n", color); + return -1; + } +} + int main(int argc, char **argv) { android::ProcessState::self()->startThreadPool(); DataSource::RegisterDefaultSniffers(); #if 1 - if (argc != 2) { - fprintf(stderr, "usage: %s filename\n", argv[0]); + if (argc != 3) { + fprintf(stderr, "usage: %s <filename> <input_color_format>\n", argv[0]); + fprintf(stderr, " <input_color_format>: 0 (YUV420SP) or 1 (YUV420P)\n"); return 1; } + int colorFormat = translateColorToOmxEnumValue(atoi(argv[2])); + if (colorFormat == -1) { + fprintf(stderr, "input color format must be 0 (YUV420SP) or 1 (YUV420P)\n"); + return 1; + } OMXClient client; CHECK_EQ(client.connect(), OK); + status_t err = OK; + #if 0 sp<MediaSource> source = createSource(argv[1]); @@ -173,7 +207,7 @@ int main(int argc, char **argv) { #else int width = 720; int height = 480; - sp<MediaSource> decoder = new DummySource(width, height); + sp<MediaSource> decoder = new DummySource(width, height, colorFormat); #endif sp<MetaData> enc_meta = new MetaData; @@ -187,7 +221,7 @@ int main(int argc, char **argv) { enc_meta->setInt32(kKeyStride, width); enc_meta->setInt32(kKeySliceHeight, height); enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec); - enc_meta->setInt32(kKeyColorFormat, kColorFormat); + enc_meta->setInt32(kKeyColorFormat, colorFormat); sp<MediaSource> encoder = OMXCodec::Create( @@ -197,14 +231,14 @@ int main(int argc, char **argv) { sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4"); writer->addSource(encoder); writer->setMaxFileDuration(kDurationUs); - writer->start(); + CHECK_EQ(OK, writer->start()); while (!writer->reachedEOS()) { fprintf(stderr, "."); usleep(100000); } - writer->stop(); + err = writer->stop(); #else - encoder->start(); + CHECK_EQ(OK, encoder->start()); MediaBuffer *buffer; while (encoder->read(&buffer) == OK) { @@ -222,7 +256,7 @@ int main(int argc, char **argv) { buffer = NULL; } - encoder->stop(); + err = encoder->stop(); #endif printf("$\n"); @@ -247,12 +281,16 @@ int main(int argc, char **argv) { buffer = NULL; } - source->stop(); + err = source->stop(); delete source; source = NULL; #endif + if (err != OK && err != ERROR_END_OF_STREAM) { + fprintf(stderr, "record failed: %d\n", err); + return 1; + } return 0; } #else diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 6e6e86f78950..72bf825ea2c3 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1427,7 +1427,9 @@ public class Activity extends ContextThemeWrapper * <li> The function will be called between {@link #onStop} and * {@link #onDestroy}. * <li> A new instance of the activity will <em>always</em> be immediately - * created after this one's {@link #onDestroy()} is called. + * created after this one's {@link #onDestroy()} is called. In particular, + * <em>no</em> messages will be dispatched during this time (when the returned + * object does not have an activity to be associated with). * <li> The object you return here will <em>always</em> be available from * the {@link #getLastNonConfigurationInstance()} method of the following * activity instance as described there. @@ -1440,6 +1442,15 @@ public class Activity extends ContextThemeWrapper * may change based on the configuration, including any data loaded from * resources such as strings, layouts, or drawables. * + * <p>The guarantee of no message handling during the switch to the next + * activity simplifies use with active objects. For example if your retained + * state is an {@link android.os.AsyncTask} you are guaranteed that its + * call back functions (like {@link android.os.AsyncTask#onPostExecute}) will + * not be called from the call here until you execute the next instance's + * {@link #onCreate(Bundle)}. (Note however that there is of course no such + * guarantee for {@link android.os.AsyncTask#doInBackground} since that is + * running in a separate thread.) + * * @return Return any Object holding the desired state to propagate to the * next activity instance. */ diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d8b525346362..3c7bebfa5d7b 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -363,7 +363,8 @@ public final class ActivityThread { private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s"; private static final String ONE_COUNT_COLUMN = "%17s %8d"; private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d"; - private static final String DB_INFO_FORMAT = " %8d %8d %10d %s"; + private static final String TWO_COUNT_COLUMNS_DB = "%20s %8d %20s %8d"; + private static final String DB_INFO_FORMAT = " %8d %8d %14d %s"; // Formatting for checkin service - update version if row format changes private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1; @@ -806,15 +807,15 @@ public final class ActivityThread { // SQLite mem info pw.println(" "); pw.println(" SQL"); - printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "memoryUsed:", + printRow(pw, TWO_COUNT_COLUMNS_DB, "heap:", sqliteAllocated, "MEMORY_USED:", stats.memoryUsed / 1024); - printRow(pw, TWO_COUNT_COLUMNS, "pageCacheOverflo:", stats.pageCacheOverflo / 1024, - "largestMemAlloc:", stats.largestMemAlloc / 1024); + printRow(pw, TWO_COUNT_COLUMNS_DB, "PAGECACHE_OVERFLOW:", + stats.pageCacheOverflo / 1024, "MALLOC_SIZE:", stats.largestMemAlloc / 1024); pw.println(" "); int N = stats.dbStats.size(); if (N > 0) { pw.println(" DATABASES"); - printRow(pw, " %8s %8s %10s %s", "Pagesize", "Dbsize", "Lookaside", "Dbname"); + printRow(pw, " %8s %8s %14s %s", "pgsz", "dbsz", "Lookaside(b)", "Dbname"); for (int i = 0; i < N; i++) { DbStats dbStats = stats.dbStats.get(i); printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize, diff --git a/core/java/android/app/backup/package.html b/core/java/android/app/backup/package.html index ae29994ab5a9..e14034973ddd 100644 --- a/core/java/android/app/backup/package.html +++ b/core/java/android/app/backup/package.html @@ -3,6 +3,9 @@ <p>Contains the backup and restore functionality available to applications. If a user wipes the data on their device or upgrades to a new Android-powered device, all applications that have enabled backup will restore the user's previous data.</p> + +<p>For a detailed guide to using the backup APIs, see the <a +href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p> {@more} <p>All backup and restore operations are controlled by the {@link @@ -22,8 +25,5 @@ employing backup helpers such as {@link android.app.backup.SharedPreferencesBack <li>Restore the data saved to remote storage</li> </ul> -<p>For a detailed guide to using the backup APIs, see the <a -href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p> - </BODY> </HTML> diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java index 89c3f96a7783..b2a166b06fdf 100644 --- a/core/java/android/database/sqlite/SQLiteDebug.java +++ b/core/java/android/database/sqlite/SQLiteDebug.java @@ -134,7 +134,7 @@ public final class SQLiteDebug { public DbStats(String dbName, long pageCount, long pageSize, int lookaside) { this.dbName = dbName; - this.pageSize = pageSize; + this.pageSize = pageSize / 1024; dbSize = (pageCount * pageSize) / 1024; this.lookaside = lookaside; } diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 26600f35da5f..0d8228ce1e1a 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -1182,14 +1182,17 @@ public class Camera { public static final String FOCUS_MODE_EDOF = "edof"; /** - * Continuous auto focus mode. The camera continuously tries to focus. - * This is ideal for shooting video or shooting photo of moving object. - * Auto focus starts when the parameter is set. Applications should not - * call {@link #autoFocus(AutoFocusCallback)} in this mode. To stop - * continuous focus, applications should change the focus mode to other - * modes. - */ - public static final String FOCUS_MODE_CONTINUOUS = "continuous"; + * Continuous auto focus mode intended for video recording. The camera + * continuously tries to focus. This is ideal for shooting video. + * Applications still can call {@link + * #takePicture(Camera.ShutterCallback, Camera.PictureCallback, + * Camera.PictureCallback)} in this mode but the subject may not be in + * focus. Auto focus starts when the parameter is set. Applications + * should not call {@link #autoFocus(AutoFocusCallback)} in this mode. + * To stop continuous focus, applications should change the focus mode + * to other modes. + */ + public static final String FOCUS_MODE_CONTINUOUS_VIDEO = "continuous-video"; // Indices for focus distance array. /** @@ -2023,7 +2026,7 @@ public class Camera { * @see #FOCUS_MODE_MACRO * @see #FOCUS_MODE_FIXED * @see #FOCUS_MODE_EDOF - * @see #FOCUS_MODE_CONTINUOUS + * @see #FOCUS_MODE_CONTINUOUS_VIDEO */ public String getFocusMode() { return get(KEY_FOCUS_MODE); @@ -2225,8 +2228,8 @@ public class Camera { * #autoFocus(AutoFocusCallback)}, {@link #cancelAutoFocus}, or {@link * #startPreview()}. Applications can call {@link #getParameters()} * and this method anytime to get the latest focus distances. If the - * focus mode is FOCUS_MODE_CONTINUOUS, focus distances may change from - * time to time. + * focus mode is FOCUS_MODE_CONTINUOUS_VIDEO, focus distances may change + * from time to time. * * This method is intended to estimate the distance between the camera * and the subject. After autofocus, the subject distance may be within diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java index 5320da3bc75c..0e671e930062 100644 --- a/core/java/android/net/DownloadManager.java +++ b/core/java/android/net/DownloadManager.java @@ -25,7 +25,6 @@ import android.os.ParcelFileDescriptor; import android.provider.BaseColumns; import android.provider.Downloads; -import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Arrays; @@ -195,6 +194,12 @@ public class DownloadManager { public final static int ERROR_CANNOT_RESUME = 1008; /** + * Value of {@link #COLUMN_ERROR_CODE} when the requested destination file already exists (the + * download manager will not overwrite an existing file). + */ + public final static int ERROR_FILE_ALREADY_EXISTS = 1009; + + /** * Broadcast intent action sent by the download manager when a download completes. */ public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE"; @@ -235,10 +240,11 @@ public class DownloadManager { Downloads.COLUMN_URI, Downloads.COLUMN_MIME_TYPE, Downloads.COLUMN_TOTAL_BYTES, - Downloads._DATA, Downloads.COLUMN_STATUS, Downloads.COLUMN_CURRENT_BYTES, Downloads.COLUMN_LAST_MODIFICATION, + Downloads.COLUMN_DESTINATION, + Downloads.Impl.COLUMN_FILE_NAME_HINT, }; private static final Set<String> LONG_COLUMNS = new HashSet<String>( @@ -359,7 +365,6 @@ public class DownloadManager { * * @param show whether the download manager should show a notification for this download. * @return this object - * @hide */ public Request setShowRunningNotification(boolean show) { mShowNotification = show; @@ -820,15 +825,10 @@ public class DownloadManager { } private String getLocalUri() { - String localUri = getUnderlyingString(Downloads.Impl._DATA); - if (localUri == null) { - return null; - } - long destinationType = getUnderlyingLong(Downloads.Impl.COLUMN_DESTINATION); if (destinationType == Downloads.Impl.DESTINATION_FILE_URI) { - // return file URI for external download - return Uri.fromFile(new File(localUri)).toString(); + // return client-provided file URI for external download + return getUnderlyingString(Downloads.Impl.COLUMN_FILE_NAME_HINT); } // return content URI for cache download @@ -894,6 +894,9 @@ public class DownloadManager { case Downloads.Impl.STATUS_CANNOT_RESUME: return ERROR_CANNOT_RESUME; + case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR: + return ERROR_FILE_ALREADY_EXISTS; + default: return ERROR_UNKNOWN; } diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java index 4039a690de57..3ee8a80e9968 100644 --- a/core/java/android/net/LocalSocket.java +++ b/core/java/android/net/LocalSocket.java @@ -70,8 +70,11 @@ public class LocalSocket { if (!implCreated) { synchronized (this) { if (!implCreated) { - implCreated = true; - impl.create(true); + try { + impl.create(true); + } finally { + implCreated = true; + } } } } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 1e88c5647666..ba8014f2a3fa 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -397,7 +397,7 @@ public abstract class BatteryStats implements Parcelable { } } - public final class HistoryItem implements Parcelable { + public final static class HistoryItem implements Parcelable { public HistoryItem next; public long time; @@ -482,6 +482,18 @@ public abstract class BatteryStats implements Parcelable { dest.writeInt(states); } + public void setTo(HistoryItem o) { + time = o.time; + cmd = o.cmd; + batteryLevel = o.batteryLevel; + batteryStatus = o.batteryStatus; + batteryHealth = o.batteryHealth; + batteryPlugType = o.batteryPlugType; + batteryTemperature = o.batteryTemperature; + batteryVoltage = o.batteryVoltage; + states = o.states; + } + public void setTo(long time, byte cmd, HistoryItem o) { this.time = time; this.cmd = cmd; @@ -526,6 +538,10 @@ public abstract class BatteryStats implements Parcelable { } } + public abstract boolean startIteratingHistoryLocked(); + + public abstract boolean getNextHistoryLocked(HistoryItem out); + /** * Return the current history of battery state changes. */ @@ -1688,8 +1704,8 @@ public abstract class BatteryStats implements Parcelable { */ @SuppressWarnings("unused") public void dumpLocked(PrintWriter pw) { - HistoryItem rec = getHistory(); - if (rec != null) { + final HistoryItem rec = new HistoryItem(); + if (startIteratingHistoryLocked()) { pw.println("Battery History:"); long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); int oldState = 0; @@ -1698,7 +1714,7 @@ public abstract class BatteryStats implements Parcelable { int oldPlug = -1; int oldTemp = -1; int oldVolt = -1; - while (rec != null) { + while (getNextHistoryLocked(rec)) { pw.print(" "); TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); pw.print(" "); @@ -1803,7 +1819,6 @@ public abstract class BatteryStats implements Parcelable { pw.println(); } oldState = rec.states; - rec = rec.next; } pw.println(""); } diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 5fea6fec453f..e56e25774d0f 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -307,8 +307,10 @@ public class RecoverySystem { * Requires the {@link android.Manifest.permission#REBOOT} permission. * * @param context the Context to use - * @param packageFile the update package to install. Currently - * must be on the /cache or /data partitions. + * @param packageFile the update package to install. Must be on + * a partition mountable by recovery. (The set of partitions + * known to recovery may vary from device to device. Generally, + * /cache and /data are safe.) * * @throws IOException if writing the recovery command file * fails, or if the reboot itself fails. @@ -316,15 +318,6 @@ public class RecoverySystem { public static void installPackage(Context context, File packageFile) throws IOException { String filename = packageFile.getCanonicalPath(); - - if (filename.startsWith("/cache/")) { - filename = "CACHE:" + filename.substring(7); - } else if (filename.startsWith("/data/")) { - filename = "DATA:" + filename.substring(6); - } else { - throw new IllegalArgumentException( - "Must start with /cache or /data: " + filename); - } Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!"); String arg = "--update_package=" + filename; bootCommand(context, arg); diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java index 74c7372144bd..1e358c9d0281 100644 --- a/core/java/android/provider/Downloads.java +++ b/core/java/android/provider/Downloads.java @@ -895,6 +895,14 @@ public final class Downloads { */ public static final String COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI = "is_visible_in_downloads_ui"; + /** + * If true, the user has confirmed that this download can proceed over the mobile network + * even though it exceeds the recommended maximum size. + * <P>Type: BOOLEAN</P> + */ + public static final String COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT = + "bypass_recommended_size_limit"; + /* * Lists the destinations that an application can specify for a download. */ @@ -1077,7 +1085,12 @@ public final class Downloads { /** * The lowest-valued error status that is not an actual HTTP status code. */ - public static final int MIN_ARTIFICIAL_ERROR_STATUS = 489; + public static final int MIN_ARTIFICIAL_ERROR_STATUS = 488; + + /** + * The requested destination file already exists. + */ + public static final int STATUS_FILE_ALREADY_EXISTS_ERROR = 488; /** * Some possibly transient error occurred, but we can't resume the download. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index fd601159981d..69151dff34d0 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3428,6 +3428,15 @@ public final class Settings { "download_manager_max_bytes_over_mobile"; /** + * The recommended maximum size, in bytes, of a download that the download manager should + * transfer over a non-wifi connection. Over this size, the use will be warned, but will + * have the option to start the download over the mobile connection anyway. + * @hide + */ + public static final String DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE = + "download_manager_recommended_max_bytes_over_mobile"; + + /** * ms during which to consume extra events related to Inet connection condition * after a transtion to fully-connected * @hide diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 456e0d9dd6e2..c9835a01003f 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -1284,13 +1284,18 @@ public class WebView extends AbsoluteLayout return mDatabase.getHttpAuthUsernamePassword(host, realm); } + private void clearHelpers() { + clearTextEntry(false); + selectionDone(); + } + /** * Destroy the internal state of the WebView. This method should be called * after the WebView has been removed from the view system. No other * methods may be called on a WebView after destroy. */ public void destroy() { - clearTextEntry(false); + clearHelpers(); if (mWebViewCore != null) { // Set the handlers to null before destroying WebViewCore so no // more messages will be posted. @@ -1608,7 +1613,7 @@ public class WebView extends AbsoluteLayout arg.mUrl = url; arg.mExtraHeaders = extraHeaders; mWebViewCore.sendMessage(EventHub.LOAD_URL, arg); - clearTextEntry(false); + clearHelpers(); } /** @@ -1637,7 +1642,7 @@ public class WebView extends AbsoluteLayout arg.mUrl = url; arg.mPostData = postData; mWebViewCore.sendMessage(EventHub.POST_URL, arg); - clearTextEntry(false); + clearHelpers(); } else { loadUrl(url); } @@ -1693,7 +1698,7 @@ public class WebView extends AbsoluteLayout arg.mEncoding = encoding; arg.mHistoryUrl = historyUrl; mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg); - clearTextEntry(false); + clearHelpers(); } /** @@ -1710,7 +1715,7 @@ public class WebView extends AbsoluteLayout * Reload the current url. */ public void reload() { - clearTextEntry(false); + clearHelpers(); switchOutDrawHistory(); mWebViewCore.sendMessage(EventHub.RELOAD); } @@ -1790,7 +1795,7 @@ public class WebView extends AbsoluteLayout private void goBackOrForward(int steps, boolean ignoreSnapshot) { if (steps != 0) { - clearTextEntry(false); + clearHelpers(); mWebViewCore.sendMessage(EventHub.GO_BACK_FORWARD, steps, ignoreSnapshot ? 1 : 0); } @@ -4421,7 +4426,7 @@ public class WebView extends AbsoluteLayout @Override protected void onDetachedFromWindow() { - clearTextEntry(false); + clearHelpers(); dismissZoomControl(); if (hasWindowFocus()) setActive(false); super.onDetachedFromWindow(); diff --git a/core/java/android/widget/EdgeGlow.java b/core/java/android/widget/EdgeGlow.java index 93222e1c00fc..e24f49543496 100644 --- a/core/java/android/widget/EdgeGlow.java +++ b/core/java/android/widget/EdgeGlow.java @@ -36,25 +36,26 @@ public class EdgeGlow { private static final int PULL_TIME = 250; // Time it will take for a pulled glow to decay to partial strength before release - private static final int PULL_DECAY_TIME = 1000; + private static final int PULL_DECAY_TIME = 10000; + private static final float MAX_ALPHA = 1.f; private static final float HELD_EDGE_ALPHA = 0.7f; private static final float HELD_EDGE_SCALE_Y = 0.5f; private static final float HELD_GLOW_ALPHA = 0.5f; private static final float HELD_GLOW_SCALE_Y = 0.5f; - private static final float MAX_GLOW_HEIGHT = 0.33f; + private static final float MAX_GLOW_HEIGHT = 3.f; - private static final float PULL_GLOW_BEGIN = 0.5f; + private static final float PULL_GLOW_BEGIN = 1.f; private static final float PULL_EDGE_BEGIN = 0.6f; // Minimum velocity that will be absorbed - private static final int MIN_VELOCITY = 750; - + private static final int MIN_VELOCITY = 100; + private static final float EPSILON = 0.001f; - private Drawable mEdge; - private Drawable mGlow; + private final Drawable mEdge; + private final Drawable mGlow; private int mWidth; private int mHeight; @@ -73,9 +74,9 @@ public class EdgeGlow { private float mGlowScaleYFinish; private long mStartTime; - private int mDuration; + private float mDuration; - private Interpolator mInterpolator; + private final Interpolator mInterpolator; private static final int STATE_IDLE = 0; private static final int STATE_PULL = 1; @@ -83,6 +84,17 @@ public class EdgeGlow { private static final int STATE_RECEDE = 3; private static final int STATE_PULL_DECAY = 4; + // How much dragging should effect the height of the edge image. + // Number determined by user testing. + private static final int PULL_DISTANCE_EDGE_FACTOR = 5; + + // How much dragging should effect the height of the glow image. + // Number determined by user testing. + private static final int PULL_DISTANCE_GLOW_FACTOR = 10; + + private static final int VELOCITY_EDGE_FACTOR = 8; + private static final int VELOCITY_GLOW_FACTOR = 16; + private int mState = STATE_IDLE; private float mPullDistance; @@ -109,6 +121,7 @@ public class EdgeGlow { /** * Call when the object is pulled by the user. + * * @param deltaDistance Change in distance since the last call */ public void onPull(float deltaDistance) { @@ -127,11 +140,12 @@ public class EdgeGlow { mPullDistance += deltaDistance; float distance = Math.abs(mPullDistance); - mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, 1.f)); - mEdgeScaleY = mEdgeScaleYStart = Math.max(HELD_EDGE_SCALE_Y, Math.min(distance, 2.f)); + mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA)); + mEdgeScaleY = mEdgeScaleYStart = Math.max( + HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f)); - mGlowAlpha = mGlowAlphaStart = Math.max(0.5f, - Math.min(mGlowAlpha + Math.abs(deltaDistance), 1.f)); + mGlowAlpha = mGlowAlphaStart = Math.max( + 0.5f, Math.min(mGlowAlpha + Math.abs(deltaDistance), MAX_ALPHA)); float glowChange = Math.abs(deltaDistance); if (deltaDistance > 0 && mPullDistance < 0) { @@ -140,7 +154,8 @@ public class EdgeGlow { if (mPullDistance == 0) { mGlowScaleY = 0; } - mGlowScaleY = mGlowScaleYStart = Math.max(0, mGlowScaleY + glowChange * 2); + mGlowScaleY = mGlowScaleYStart = Math.max( + 0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR); mEdgeAlphaFinish = mEdgeAlpha; mEdgeScaleYFinish = mEdgeScaleY; @@ -165,9 +180,9 @@ public class EdgeGlow { mGlowScaleYStart = mGlowScaleY; mEdgeAlphaFinish = 0.f; - mEdgeScaleYFinish = 0.1f; + mEdgeScaleYFinish = 0.f; mGlowAlphaFinish = 0.f; - mGlowScaleYFinish = 0.1f; + mGlowScaleYFinish = 0.f; mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = RECEDE_TIME; @@ -175,6 +190,7 @@ public class EdgeGlow { /** * Call when the effect absorbs an impact at the given velocity. + * * @param velocity Velocity at impact in pixels per second. */ public void onAbsorb(int velocity) { @@ -182,27 +198,43 @@ public class EdgeGlow { velocity = Math.max(MIN_VELOCITY, Math.abs(velocity)); mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mDuration = (int) (velocity * 0.03f); + mDuration = 0.1f + (velocity * 0.03f); + // The edge should always be at least partially visible, regardless + // of velocity. mEdgeAlphaStart = 0.5f; mEdgeScaleYStart = 0.2f; + // The glow depends more on the velocity, and therefore starts out + // nearly invisible. mGlowAlphaStart = 0.5f; mGlowScaleYStart = 0.f; - mEdgeAlphaFinish = Math.max(0, Math.min(velocity * 0.01f, 1)); + // Factor the velocity by 8. Testing on device shows this works best to + // reflect the strength of the user's scrolling. + mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1)); + // Edge should never get larger than the size of its asset. mEdgeScaleYFinish = 1.f; - mGlowAlphaFinish = 1.f; - mGlowScaleYFinish = Math.min(velocity * 0.001f, 1); + + // Growth for the size of the glow should be quadratic to properly + // respond + // to a user's scrolling speed. The faster the scrolling speed, the more + // intense the effect should be for both the size and the saturation. + mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f); + // Alpha should change for the glow as well as size. + mGlowAlphaFinish = Math.max( + mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); } + /** - * Draw into the provided canvas. - * Assumes that the canvas has been rotated accordingly and the size has been set. - * The effect will be drawn the full width of X=0 to X=width, emitting from Y=0 and extending - * to some factor < 1.f of height. + * Draw into the provided canvas. Assumes that the canvas has been rotated + * accordingly and the size has been set. The effect will be drawn the full + * width of X=0 to X=width, emitting from Y=0 and extending to some factor < + * 1.f of height. * * @param canvas Canvas to draw into - * @return true if drawing should continue beyond this frame to continue the animation + * @return true if drawing should continue beyond this frame to continue the + * animation */ public boolean draw(Canvas canvas) { update(); @@ -213,15 +245,14 @@ public class EdgeGlow { final float distScale = (float) mHeight / mWidth; mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255)); - mGlow.setBounds(0, 0, mWidth, (int) Math.min(glowHeight * mGlowScaleY * distScale * 0.6f, - mHeight * MAX_GLOW_HEIGHT)); + // Width of the image should be 3 * the width of the screen. + // Should start off screen to the left. + mGlow.setBounds(-mWidth, 0, mWidth * 2, (int) Math.min( + glowHeight * mGlowScaleY * distScale * 0.6f, mHeight * MAX_GLOW_HEIGHT)); mGlow.draw(canvas); mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255)); - mEdge.setBounds(0, - 0, - mWidth, - (int) (edgeHeight * mEdgeScaleY)); + mEdge.setBounds(0, 0, mWidth, (int) (edgeHeight * mEdgeScaleY)); mEdge.draw(canvas); return mState != STATE_IDLE; @@ -229,7 +260,7 @@ public class EdgeGlow { private void update() { final long time = AnimationUtils.currentAnimationTimeMillis(); - final float t = Math.min((float) (time - mStartTime) / mDuration, 1.f); + final float t = Math.min((time - mStartTime) / mDuration, 1.f); final float interp = mInterpolator.getInterpolation(t); @@ -251,7 +282,7 @@ public class EdgeGlow { mGlowScaleYStart = mGlowScaleY; mEdgeAlphaFinish = 0.f; - mEdgeScaleYFinish = 0.1f; + mEdgeScaleYFinish = mEdgeScaleY; mGlowAlphaFinish = 0.f; mGlowScaleYFinish = mGlowScaleY; break; @@ -265,10 +296,11 @@ public class EdgeGlow { mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; - mEdgeAlphaFinish = Math.min(mEdgeAlphaStart, HELD_EDGE_ALPHA); - mEdgeScaleYFinish = Math.min(mEdgeScaleYStart, HELD_EDGE_SCALE_Y); - mGlowAlphaFinish = Math.min(mGlowAlphaStart, HELD_GLOW_ALPHA); - mGlowScaleYFinish = Math.min(mGlowScaleY, HELD_GLOW_SCALE_Y); + // After a pull, the glow should fade to nothing. + mEdgeAlphaFinish = 0.f; + mEdgeScaleYFinish = 0.f; + mGlowAlphaFinish = 0.f; + mGlowScaleYFinish = 0.f; break; case STATE_PULL_DECAY: // Do nothing; wait for release diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index c2d003e96293..6e5c47fa1044 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -51,6 +51,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; /** * All information we are collecting about things that can happen that impact @@ -3834,6 +3835,22 @@ public final class BatteryStatsImpl extends BatteryStats { } } + private HistoryItem mHistoryIterator; + + public boolean startIteratingHistoryLocked() { + return (mHistoryIterator = mHistory) != null; + } + + public boolean getNextHistoryLocked(HistoryItem out) { + HistoryItem cur = mHistoryIterator; + if (cur == null) { + return false; + } + out.setTo(cur); + mHistoryIterator = cur.next; + return true; + } + @Override public HistoryItem getHistory() { return mHistory; @@ -3960,7 +3977,7 @@ public final class BatteryStatsImpl extends BatteryStats { } if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) { if (mFile != null) { - writeLocked(); + writeAsyncLocked(); } } } @@ -4356,11 +4373,22 @@ public final class BatteryStatsImpl extends BatteryStats { } public void shutdownLocked() { - writeLocked(); + writeSyncLocked(); mShuttingDown = true; } - public void writeLocked() { + Parcel mPendingWrite = null; + final ReentrantLock mWriteLock = new ReentrantLock(); + + public void writeAsyncLocked() { + writeLocked(false); + } + + public void writeSyncLocked() { + writeLocked(true); + } + + void writeLocked(boolean sync) { if (mFile == null) { Slog.w("BatteryStats", "writeLocked: no file associated with this instance"); return; @@ -4370,23 +4398,51 @@ public final class BatteryStatsImpl extends BatteryStats { return; } + Parcel out = Parcel.obtain(); + writeSummaryToParcel(out); + mLastWriteTime = SystemClock.elapsedRealtime(); + + if (mPendingWrite != null) { + mPendingWrite.recycle(); + } + mPendingWrite = out; + + if (sync) { + commitPendingDataToDisk(); + } else { + Thread thr = new Thread("BatteryStats-Write") { + @Override + public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + commitPendingDataToDisk(); + } + }; + thr.start(); + } + } + + public void commitPendingDataToDisk() { + Parcel next; + synchronized (this) { + next = mPendingWrite; + mPendingWrite = null; + + mWriteLock.lock(); + } + try { FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite()); - Parcel out = Parcel.obtain(); - writeSummaryToParcel(out); - stream.write(out.marshall()); - out.recycle(); - + stream.write(next.marshall()); stream.flush(); stream.close(); mFile.commit(); - - mLastWriteTime = SystemClock.elapsedRealtime(); - return; } catch (IOException e) { Slog.w("BatteryStats", "Error writing battery statistics", e); + mFile.rollback(); + } finally { + next.recycle(); + mWriteLock.unlock(); } - mFile.rollback(); } static byte[] readFully(FileInputStream stream) throws java.io.IOException { diff --git a/core/res/res/drawable-hdpi/btn_circle_disable.png b/core/res/res/drawable-hdpi/btn_circle_disable.png Binary files differindex 3f859cb57a64..39652a855800 100755..100644 --- a/core/res/res/drawable-hdpi/btn_circle_disable.png +++ b/core/res/res/drawable-hdpi/btn_circle_disable.png diff --git a/core/res/res/drawable-hdpi/btn_circle_disable_focused.png b/core/res/res/drawable-hdpi/btn_circle_disable_focused.png Binary files differindex 66251b87bb74..1aa7ffe69b11 100755..100644 --- a/core/res/res/drawable-hdpi/btn_circle_disable_focused.png +++ b/core/res/res/drawable-hdpi/btn_circle_disable_focused.png diff --git a/core/res/res/drawable-hdpi/expander_ic_maximized.9.png b/core/res/res/drawable-hdpi/expander_ic_maximized.9.png Binary files differindex 0c19bb782a60..2ec27afa7725 100755..100644 --- a/core/res/res/drawable-hdpi/expander_ic_maximized.9.png +++ b/core/res/res/drawable-hdpi/expander_ic_maximized.9.png diff --git a/core/res/res/drawable-hdpi/expander_ic_minimized.9.png b/core/res/res/drawable-hdpi/expander_ic_minimized.9.png Binary files differindex 2ec27afa7725..0c19bb782a60 100755..100644 --- a/core/res/res/drawable-hdpi/expander_ic_minimized.9.png +++ b/core/res/res/drawable-hdpi/expander_ic_minimized.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png Binary files differindex 34992082225d..f8dc42ae1a24 100644 --- a/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png Binary files differindex 91eaec88c243..92b24b0d9fdf 100644 --- a/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png Binary files differindex e5bc5f69a9b0..8208b20d6697 100644 --- a/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_normal.png b/core/res/res/drawable-hdpi/jog_tab_left_normal.png Binary files differindex 5326c7c4f0c7..4c877434b915 100644 --- a/core/res/res/drawable-hdpi/jog_tab_left_normal.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_normal.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_pressed.png b/core/res/res/drawable-hdpi/jog_tab_left_pressed.png Binary files differindex 7b906dfe147b..150c73507e3f 100644 --- a/core/res/res/drawable-hdpi/jog_tab_left_pressed.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_pressed.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png Binary files differindex ea8c3157f173..11ab30c10f4f 100644 --- a/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png Binary files differindex aa0ceb943dbd..a9122855b24d 100644 --- a/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png Binary files differindex 3cfeb67e6e63..0dd84fa487b2 100644 --- a/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_normal.png b/core/res/res/drawable-hdpi/jog_tab_right_normal.png Binary files differindex da7726b262cf..e0f1a0a04876 100644 --- a/core/res/res/drawable-hdpi/jog_tab_right_normal.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_normal.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_pressed.png b/core/res/res/drawable-hdpi/jog_tab_right_pressed.png Binary files differindex 450a325b27aa..f41d6f59c5fc 100644 --- a/core/res/res/drawable-hdpi/jog_tab_right_pressed.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_pressed.png diff --git a/core/res/res/drawable-hdpi/overscroll_edge.png b/core/res/res/drawable-hdpi/overscroll_edge.png Binary files differindex f8e40ecfd7cd..5969093efc25 100644 --- a/core/res/res/drawable-hdpi/overscroll_edge.png +++ b/core/res/res/drawable-hdpi/overscroll_edge.png diff --git a/core/res/res/drawable-hdpi/popup_center_dark.9.png b/core/res/res/drawable-hdpi/popup_center_dark.9.png Binary files differindex e2e983f3f0a2..ac1f92dfff88 100755..100644 --- a/core/res/res/drawable-hdpi/popup_center_dark.9.png +++ b/core/res/res/drawable-hdpi/popup_center_dark.9.png diff --git a/core/res/res/drawable-hdpi/stat_notify_chat.png b/core/res/res/drawable-hdpi/stat_notify_chat.png Binary files differindex 097a979a5c7b..71ea8de6b682 100755..100644 --- a/core/res/res/drawable-hdpi/stat_notify_chat.png +++ b/core/res/res/drawable-hdpi/stat_notify_chat.png diff --git a/core/res/res/drawable-mdpi/expander_ic_maximized.9.png b/core/res/res/drawable-mdpi/expander_ic_maximized.9.png Binary files differindex 465cabd7e929..d5c32766cece 100644 --- a/core/res/res/drawable-mdpi/expander_ic_maximized.9.png +++ b/core/res/res/drawable-mdpi/expander_ic_maximized.9.png diff --git a/core/res/res/drawable-mdpi/expander_ic_minimized.9.png b/core/res/res/drawable-mdpi/expander_ic_minimized.9.png Binary files differindex 9967ecbd6c1e..4515b42177bb 100644 --- a/core/res/res/drawable-mdpi/expander_ic_minimized.9.png +++ b/core/res/res/drawable-mdpi/expander_ic_minimized.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_confirm_gray.png b/core/res/res/drawable-mdpi/jog_tab_left_confirm_gray.png Binary files differindex e8544ff9515a..b5d3290b4a9b 100644 --- a/core/res/res/drawable-mdpi/jog_tab_left_confirm_gray.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_confirm_gray.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_confirm_green.png b/core/res/res/drawable-mdpi/jog_tab_left_confirm_green.png Binary files differindex d0ba8f8fbed5..e4cff64100f5 100644 --- a/core/res/res/drawable-mdpi/jog_tab_left_confirm_green.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_confirm_green.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_confirm_yellow.png b/core/res/res/drawable-mdpi/jog_tab_left_confirm_yellow.png Binary files differindex 861e17a7f173..d50181447e01 100644 --- a/core/res/res/drawable-mdpi/jog_tab_left_confirm_yellow.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_confirm_yellow.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_normal.png b/core/res/res/drawable-mdpi/jog_tab_left_normal.png Binary files differindex 7af1b855006b..42f7e39d2d54 100644 --- a/core/res/res/drawable-mdpi/jog_tab_left_normal.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_normal.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_pressed.png b/core/res/res/drawable-mdpi/jog_tab_left_pressed.png Binary files differindex b76e83e9573e..888f19b5e7fc 100644 --- a/core/res/res/drawable-mdpi/jog_tab_left_pressed.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_pressed.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_confirm_gray.png b/core/res/res/drawable-mdpi/jog_tab_right_confirm_gray.png Binary files differindex 814a50d25756..7fc930ebf931 100644 --- a/core/res/res/drawable-mdpi/jog_tab_right_confirm_gray.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_confirm_gray.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_confirm_green.png b/core/res/res/drawable-mdpi/jog_tab_right_confirm_green.png Binary files differindex cf157fc837ed..1a08be8a81e2 100644 --- a/core/res/res/drawable-mdpi/jog_tab_right_confirm_green.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_confirm_green.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_confirm_yellow.png b/core/res/res/drawable-mdpi/jog_tab_right_confirm_yellow.png Binary files differindex 66557319d14f..2aa40363aec7 100644 --- a/core/res/res/drawable-mdpi/jog_tab_right_confirm_yellow.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_confirm_yellow.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_normal.png b/core/res/res/drawable-mdpi/jog_tab_right_normal.png Binary files differindex 479c9a5f2f52..10710fbb01c6 100644 --- a/core/res/res/drawable-mdpi/jog_tab_right_normal.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_normal.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_pressed.png b/core/res/res/drawable-mdpi/jog_tab_right_pressed.png Binary files differindex 454aaf2216de..021e96ba2c42 100644 --- a/core/res/res/drawable-mdpi/jog_tab_right_pressed.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_pressed.png diff --git a/core/res/res/drawable-mdpi/overscroll_edge.png b/core/res/res/drawable-mdpi/overscroll_edge.png Binary files differnew file mode 100644 index 000000000000..22f4ef88a464 --- /dev/null +++ b/core/res/res/drawable-mdpi/overscroll_edge.png diff --git a/core/res/res/drawable-mdpi/overscroll_glow.png b/core/res/res/drawable-mdpi/overscroll_glow.png Binary files differnew file mode 100644 index 000000000000..761fb74c3692 --- /dev/null +++ b/core/res/res/drawable-mdpi/overscroll_glow.png diff --git a/core/res/res/drawable-mdpi/text_select_handle_middle.png b/core/res/res/drawable-mdpi/text_select_handle_middle.png Binary files differnew file mode 100644 index 000000000000..201e7f9f5fab --- /dev/null +++ b/core/res/res/drawable-mdpi/text_select_handle_middle.png diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index f09421bca74f..487a00daa66c 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -35,6 +35,7 @@ android:label="@string/permlab_testDenied" android:description="@string/permdesc_testDenied" /> + <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> diff --git a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java index ee0f5f14516d..a7ec7d5fd523 100644 --- a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java +++ b/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java @@ -27,6 +27,7 @@ import android.net.NetworkInfo; import android.net.DownloadManager.Query; import android.net.DownloadManager.Request; import android.net.wifi.WifiManager; +import android.os.Bundle; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.SystemClock; @@ -43,9 +44,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.util.concurrent.TimeoutException; +import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Random; +import java.util.Set; import java.util.Vector; import junit.framework.AssertionFailedError; @@ -67,6 +71,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { protected static final String LOG_TAG = "android.net.DownloadManagerBaseTest"; protected static final int HTTP_OK = 200; + protected static final int HTTP_REDIRECT = 307; protected static final int HTTP_PARTIAL_CONTENT = 206; protected static final int HTTP_NOT_FOUND = 404; protected static final int HTTP_SERVICE_UNAVAILABLE = 503; @@ -119,6 +124,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { public static class MultipleDownloadsCompletedReceiver extends BroadcastReceiver { private volatile int mNumDownloadsCompleted = 0; + private Set<Long> downloadIds = Collections.synchronizedSet(new HashSet<Long>()); /** * {@inheritDoc} @@ -129,6 +135,8 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { ++mNumDownloadsCompleted; Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " + intent.getAction() + " --> total count: " + mNumDownloadsCompleted); + Bundle extras = intent.getExtras(); + downloadIds.add(new Long(extras.getLong(DownloadManager.EXTRA_DOWNLOAD_ID))); } } @@ -142,6 +150,18 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { public int numDownloadsCompleted() { return mNumDownloadsCompleted; } + + /** + * Gets the list of download IDs. + * @return A Set<Long> with the ids of the completed downloads. + */ + public Set<Long> getDownloadIds() { + synchronized(downloadIds) { + Set<Long> returnIds = new HashSet<Long>(downloadIds); + return returnIds; + } + } + } public static class WiFiChangedReceiver extends BroadcastReceiver { @@ -196,6 +216,17 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { } /** + * Helper to enqueue a response from the MockWebServer with no body. + * + * @param status The HTTP status code to return for this response + * @return Returns the mock web server response that was queued (which can be modified) + */ + protected MockResponse enqueueResponse(int status) { + return doEnqueueResponse(status); + + } + + /** * Helper to enqueue a response from the MockWebServer. * * @param status The HTTP status code to return for this response diff --git a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java b/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java index be3cbf729458..a61f02d637df 100644 --- a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java +++ b/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; +import android.net.DownloadManager; import android.net.DownloadManager.Query; import android.net.DownloadManager.Request; import android.net.DownloadManagerBaseTest.DataType; @@ -28,6 +29,7 @@ import android.net.DownloadManagerBaseTest.MultipleDownloadsCompletedReceiver; import android.net.wifi.WifiManager; import android.os.Environment; import android.os.ParcelFileDescriptor; +import android.os.StatFs; import android.os.SystemClock; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; @@ -36,10 +38,13 @@ import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import java.io.File; +import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.net.URL; +import java.util.Iterator; import java.util.Random; +import java.util.Set; import junit.framework.AssertionFailedError; @@ -51,8 +56,11 @@ import coretestutils.http.MockWebServer; */ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { - private static String LOG_TAG = "android.net.DownloadManagerIntegrationTest"; - private static String PROHIBITED_DIRECTORY = "/system"; + private final static String LOG_TAG = "android.net.DownloadManagerIntegrationTest"; + private final static String PROHIBITED_DIRECTORY = + Environment.getRootDirectory().getAbsolutePath(); + private final static String CACHE_DIR = + Environment.getDownloadCacheDirectory().getAbsolutePath(); protected MultipleDownloadsCompletedReceiver mReceiver = null; /** @@ -74,25 +82,48 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { public void tearDown() throws Exception { super.tearDown(); setWiFiStateOn(true); + removeAllCurrentDownloads(); if (mReceiver != null) { mContext.unregisterReceiver(mReceiver); mReceiver = null; - removeAllCurrentDownloads(); } } /** * Helper that does the actual basic download verification. */ - protected void doBasicDownload(byte[] blobData) throws Exception { + protected long doBasicDownload(byte[] blobData) throws Exception { long dlRequest = doStandardEnqueue(blobData); // wait for the download to complete waitForDownloadOrTimeout(dlRequest); - verifyAndCleanupSingleFileDownload(dlRequest, blobData); assertEquals(1, mReceiver.numDownloadsCompleted()); + return dlRequest; + } + + /** + * Verifies a particular error code was received from a download + * + * @param uri The uri to enqueue to the DownloadManager + * @param error The error code expected + * @throws an Exception if the test fails + */ + @LargeTest + public void doErrorTest(Uri uri, int error) throws Exception { + Request request = new Request(uri); + request.setTitle(DEFAULT_FILENAME); + + long dlRequest = mDownloadManager.enqueue(request); + waitForDownloadOrTimeout(dlRequest); + + Cursor cursor = getCursor(dlRequest); + try { + verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE, error); + } finally { + cursor.close(); + } } /** @@ -103,7 +134,8 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { int fileSize = 500 * 1024; // 500k byte[] blobData = generateData(fileSize, DataType.BINARY); - doBasicDownload(blobData); + long dlRequest = doBasicDownload(blobData); + verifyAndCleanupSingleFileDownload(dlRequest, blobData); } /** @@ -114,7 +146,8 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { int fileSize = 300000; byte[] blobData = generateData(fileSize, DataType.TEXT); - doBasicDownload(blobData); + long dlRequest = doBasicDownload(blobData); + verifyAndCleanupSingleFileDownload(dlRequest, blobData); } /** @@ -348,34 +381,209 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { } /** - * Tests trying to download two large files (50M bytes, followed by 60M bytes) + * Tests downloading a file to cache when there isn't enough space in the cache to hold the + * entire file. */ @LargeTest - public void testInsufficientSpaceSingleFiles() throws Exception { - long fileSize1 = 50000000L; - long fileSize2 = 60000000L; - File largeFile1 = createFileOnSD(null, fileSize1, DataType.TEXT, null); - File largeFile2 = createFileOnSD(null, fileSize2, DataType.TEXT, null); + public void testDownloadToCache_whenFull() throws Exception { + int DOWNLOAD_FILE_SIZE = 500000; + + StatFs fs = new StatFs(CACHE_DIR); + Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks()); + Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize()); + + int blockSize = fs.getBlockSize(); + int availableBlocks = fs.getAvailableBlocks(); + int availableBytes = blockSize * availableBlocks; + File outFile = null; try { - long dlRequest = doStandardEnqueue(largeFile1); - waitForDownloadOrTimeout(dlRequest); - ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); - verifyFileContents(pfd, largeFile1); - verifyFileSize(pfd, largeFile1.length()); + // fill cache to ensure we don't have enough space - take half the size of the + // download size, and leave that much freespace left on the cache partition + if (DOWNLOAD_FILE_SIZE <= availableBytes) { + int writeSizeBytes = availableBytes - (DOWNLOAD_FILE_SIZE / 2); + + int writeSizeBlocks = writeSizeBytes / blockSize; + int remainderSizeBlocks = availableBlocks - writeSizeBlocks; + + FileOutputStream fo = null; + try { + outFile = File.createTempFile("DM_TEST", null, new File(CACHE_DIR)); + Log.v(LOG_TAG, "writing " + writeSizeBlocks + " blocks to file " + + outFile.getAbsolutePath()); + + fo = new FileOutputStream(outFile); + + byte[] buffer = new byte[blockSize]; + while (fs.getAvailableBlocks() >= remainderSizeBlocks) { + fo.write(buffer); + fs.restat(CACHE_DIR); + } + } catch (IOException e) { + Log.e(LOG_TAG, "error filling file: ", e); + throw e; + } finally { + if (fo != null) { + fo.close(); + } + } + } - dlRequest = doStandardEnqueue(largeFile2); - waitForDownloadOrTimeout(dlRequest); - Cursor cursor = getCursor(dlRequest); - try { - verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE, - DownloadManager.ERROR_INSUFFICIENT_SPACE); - } finally { - cursor.close(); + assertTrue(DOWNLOAD_FILE_SIZE > (fs.getAvailableBlocks() * blockSize)); + byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT); + long dlRequest = doBasicDownload(blobData); + verifyAndCleanupSingleFileDownload(dlRequest, blobData); + + } finally { + if (outFile != null) { + outFile.delete(); } + } + } + + /** + * Tests that files are not deleted when DOWNLOAD_CACHE_NON_PURGEABLE is set, even if we've + * run out of space. + */ + @LargeTest + public void testDownloadCacheNonPurgeable() throws Exception { + int fileSize = 10000000; + byte[] blobData = generateData(fileSize, DataType.BINARY); + long dlRequest = -1; + + // Fill up the cache partition until there's not enough room for another download. + // Note that we need to initiate a download first, then check for the available space. This + // is b/c there could be some files that are still left in the cache that can (and will be) + // cleared out, but not until DM gets a request for a download and reclaims that + // space first. + boolean spaceAvailable = true; + while (spaceAvailable) { + dlRequest = doStandardEnqueue(blobData); + waitForDownloadOrTimeout(dlRequest); + + // Check if we've filled up the cache yet + StatFs fs = new StatFs(CACHE_DIR); + Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks()); + Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize()); + int availableBytes = fs.getBlockSize() * fs.getAvailableBlocks(); + spaceAvailable = (availableBytes > fileSize) ? true : false; + } + + // Now add one more download (should not fit in the space left over) + dlRequest = doStandardEnqueue(blobData); + waitForDownloadOrTimeout(dlRequest); + + // For the last download we should have failed b/c there is not enough space left in cache + Cursor cursor = getCursor(dlRequest); + try { + verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE, + DownloadManager.ERROR_INSUFFICIENT_SPACE); + } finally { + cursor.close(); + } + } + + /** + * Tests that we get the correct download ID from the download notification. + */ + @LargeTest + public void testGetDownloadIdOnNotification() throws Exception { + byte[] blobData = generateData(3000, DataType.TEXT); // file size = 3000 bytes + + MockResponse response = enqueueResponse(HTTP_OK, blobData); + long dlRequest = doCommonStandardEnqueue(); + waitForDownloadOrTimeout(dlRequest); + + Set<Long> ids = mReceiver.getDownloadIds(); + assertEquals(1, ids.size()); + Iterator<Long> it = ids.iterator(); + assertEquals("Download ID received from notification does not match initial id!", + dlRequest, it.next().longValue()); + } + + /** + * Tests the download failure error after too many redirects (>5). + */ + @LargeTest + public void testErrorTooManyRedirects() throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + + // force 6 redirects + for (int i = 0; i < 6; ++i) { + MockResponse response = enqueueResponse(HTTP_REDIRECT); + response.addHeader("Location", uri.toString()); + } + doErrorTest(uri, DownloadManager.ERROR_TOO_MANY_REDIRECTS); + } + + /** + * Tests the download failure error from an unhandled HTTP status code + */ + @LargeTest + public void testErrorUnhandledHttpCode() throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + MockResponse response = enqueueResponse(HTTP_PARTIAL_CONTENT); + + doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE); + } + + /** + * Tests the download failure error from an unhandled HTTP status code + */ + @LargeTest + public void testErrorHttpDataError_invalidRedirect() throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + MockResponse response = enqueueResponse(HTTP_REDIRECT); + response.addHeader("Location", "://blah.blah.blah.com"); + + doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR); + } + + /** + * Tests that we can remove a download from the download manager. + */ + @LargeTest + public void testRemoveDownload() throws Exception { + int fileSize = 100 * 1024; // 100k + byte[] blobData = generateData(fileSize, DataType.BINARY); + + long dlRequest = doBasicDownload(blobData); + Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest)); + try { + assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount()); + mDownloadManager.remove(dlRequest); + cursor.requery(); + assertEquals("The count of downloads with this ID is not 0!", 0, cursor.getCount()); + } finally { + cursor.close(); + } + } + + /** + * Tests that we can set the title of a download. + */ + @LargeTest + public void testSetTitle() throws Exception { + int fileSize = 50 * 1024; // 50k + byte[] blobData = generateData(fileSize, DataType.BINARY); + MockResponse response = enqueueResponse(HTTP_OK, blobData); + + // An arbitrary unicode string title + final String title = "\u00a5123;\"\u0152\u017d \u054b \u0a07 \ucce0 \u6820\u03a8\u5c34" + + "\uf4ad\u0da9\uc0c5\uc1a8 \uf4c5 \uf4aa\u0023\'"; + + Uri uri = getServerUri(DEFAULT_FILENAME); + Request request = new Request(uri); + request.setTitle(title); + + long dlRequest = mDownloadManager.enqueue(request); + waitForDownloadOrTimeout(dlRequest); + + Cursor cursor = getCursor(dlRequest); + try { + verifyString(cursor, DownloadManager.COLUMN_TITLE, title); } finally { - largeFile1.delete(); - largeFile2.delete(); + cursor.close(); } } } diff --git a/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java b/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java index ed280c916ec4..df781bf46676 100644 --- a/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java +++ b/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java @@ -54,8 +54,10 @@ public class DownloadManagerHostTests extends DeviceTestCase { private static final String EXTERNAL_DOWNLOAD_URI_KEY = "external_download_uri"; // Note: External environment variable ANDROID_TEST_EXTERNAL_URI must be set to point to the // external URI under which the files downloaded by the tests can be found. Note that the Uri - // must be accessible by the device during a test run. - private static String EXTERNAL_DOWNLOAD_URI_VALUE = null; + // must be accessible by the device during a test run. Correspondingly, + // ANDROID_TEST_EXTERNAL_LARGE_URI should point to the external URI of the folder containing + // large files. + private static String externalDownloadUriValue = null; Hashtable<String, String> mExtraParams = null; @@ -69,8 +71,8 @@ public class DownloadManagerHostTests extends DeviceTestCase { // ensure apk path has been set before test is run assertNotNull(getTestAppPath()); mPMUtils = new PackageManagerHostTestUtils(getDevice()); - EXTERNAL_DOWNLOAD_URI_VALUE = System.getenv("ANDROID_TEST_EXTERNAL_URI"); - assertNotNull(EXTERNAL_DOWNLOAD_URI_VALUE); + externalDownloadUriValue = System.getenv("ANDROID_TEST_EXTERNAL_URI"); + assertNotNull(externalDownloadUriValue); mExtraParams = getExtraParams(); } @@ -79,7 +81,7 @@ public class DownloadManagerHostTests extends DeviceTestCase { */ protected Hashtable<String, String> getExtraParams() { Hashtable<String, String> extraParams = new Hashtable<String, String>(); - extraParams.put(EXTERNAL_DOWNLOAD_URI_KEY, EXTERNAL_DOWNLOAD_URI_VALUE); + extraParams.put(EXTERNAL_DOWNLOAD_URI_KEY, externalDownloadUriValue); return extraParams; } @@ -198,4 +200,19 @@ public class DownloadManagerHostTests extends DeviceTestCase { DOWNLOAD_TEST_RUNNER_NAME, mExtraParams); assertTrue(testPassed); } + + /** + * Spawns a device-based function to test 15 concurrent downloads of 5,000,000-byte files + * + * @throws Exception if the test failed at any point + */ + public void testDownloadMultipleSimultaneously() throws Exception { + mPMUtils.installAppAndVerifyExistsOnDevice(String.format("%s%s%s", getTestAppPath(), + File.separator, FILE_DOWNLOAD_APK), FILE_DOWNLOAD_PKG, true); + + boolean testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG, + FILE_DOWNLOAD_CLASS, "runDownloadMultipleSimultaneously", + DOWNLOAD_TEST_RUNNER_NAME, mExtraParams); + assertTrue(testPassed); + } } diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java index ef8135398583..0293ded853c1 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java @@ -35,6 +35,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; +import java.util.HashSet; import coretestutils.http.MockResponse; import coretestutils.http.MockWebServer; @@ -55,8 +56,13 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { protected static String DOWNLOAD_10MB_FILENAME = "External10mb.apk"; protected static long DOWNLOAD_10MB_FILESIZE = 10258741; + private static final String FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX = "file"; + private static final String FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION = ".bin"; + protected static long CONCURRENT_DOWNLOAD_FILESIZE = 1000000; + // Values to be obtained from TestRunner private String externalDownloadUriValue = null; + private String externalLargeDownloadUriValue = null; /** * {@inheritDoc } @@ -65,12 +71,24 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { public void setUp() throws Exception { super.setUp(); DownloadManagerTestRunner mRunner = (DownloadManagerTestRunner)getInstrumentation(); - externalDownloadUriValue = mRunner.externalDownloadUriValue; + externalDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue); assertNotNull(externalDownloadUriValue); - if (!externalDownloadUriValue.endsWith("/")) { - externalDownloadUriValue += "/"; + externalLargeDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue); + assertNotNull(externalLargeDownloadUriValue); + } + + /** + * Normalizes a uri to ensure it ends with a "/" + * + * @param uri The uri to normalize (or null) + * @return The normalized uri, or null if null was passed in + */ + public String normalizeUri(String uri) { + if (uri != null && !uri.endsWith("/")) { + uri += "/"; } + return uri; } /** @@ -460,4 +478,37 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { downloadedFile.delete(); } } + + /** + * Tests 15 concurrent downloads of 1,000,000-byte files. + * + * @throws Exception if test failed + */ + public void runDownloadMultipleSimultaneously() throws Exception { + final int TOTAL_DOWNLOADS = 15; + HashSet<Long> downloadIds = new HashSet<Long>(TOTAL_DOWNLOADS); + MultipleDownloadsCompletedReceiver receiver = registerNewMultipleDownloadsReceiver(); + + // Make sure there are no pending downloads currently going on + removeAllCurrentDownloads(); + + try { + for (int i = 0; i < TOTAL_DOWNLOADS; ++i) { + long dlRequest = -1; + String filename = FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX + i + + FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION; + Uri remoteUri = getExternalFileUri(filename); + Request request = new Request(remoteUri); + request.setTitle(filename); + dlRequest = mDownloadManager.enqueue(request); + assertTrue(dlRequest != -1); + downloadIds.add(dlRequest); + } + + waitForDownloadsOrTimeout(DEFAULT_WAIT_POLL_TIME, 15 * 60 * 2000); // wait 15 mins max + assertEquals(TOTAL_DOWNLOADS, receiver.numDownloadsCompleted()); + } finally { + removeAllCurrentDownloads(); + } + } } diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java index 0f166195b4be..27bf7e1e2497 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java @@ -30,7 +30,7 @@ import junit.framework.TestSuite; * * To run the download manager tests: * - * adb shell am instrument -e external_download_1mb_uri <uri> external_download_500k_uri <uri> \ + * adb shell am instrument -e external_download_uri <uri> external_large_download_uri <uri> \ * -w com.android.frameworks.downloadmanagertests/.DownloadManagerTestRunner */ diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h index 7c5371aafe0c..53039a09153f 100644 --- a/include/camera/CameraParameters.h +++ b/include/camera/CameraParameters.h @@ -380,12 +380,14 @@ public: // continuously. Applications should not call // CameraHardwareInterface.autoFocus in this mode. static const char FOCUS_MODE_EDOF[]; - // Continuous auto focus mode. The camera continuously tries to focus. This - // is ideal for shooting video or shooting photo of moving object. Auto - // focus starts when the parameter is set. Applications should not call - // CameraHardwareInterface.autoFocus in this mode. To stop continuous - // focus, applications should change the focus mode to other modes. - static const char FOCUS_MODE_CONTINUOUS[]; + // Continuous auto focus mode intended for video recording. The camera + // continuously tries to focus. This is ideal for shooting video. + // Applications still can call CameraHardwareInterface.takePicture in this + // mode but the subject may not be in focus. Auto focus starts when the + // parameter is set. Applications should not call + // CameraHardwareInterface.autoFocus in this mode. To stop continuous focus, + // applications should change the focus mode to other modes. + static const char FOCUS_MODE_CONTINUOUS_VIDEO[]; private: DefaultKeyedVector<String8,String8> mMap; diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp index 362d9ee1c15b..83e5e57f1f73 100644 --- a/libs/camera/CameraParameters.cpp +++ b/libs/camera/CameraParameters.cpp @@ -142,7 +142,7 @@ const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity"; const char CameraParameters::FOCUS_MODE_MACRO[] = "macro"; const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed"; const char CameraParameters::FOCUS_MODE_EDOF[] = "edof"; -const char CameraParameters::FOCUS_MODE_CONTINUOUS[] = "continuous"; +const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video"; CameraParameters::CameraParameters() : mMap() diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java index 546bb9d84c73..ac7eb8b18e97 100644 --- a/location/java/android/location/Geocoder.java +++ b/location/java/android/location/Geocoder.java @@ -41,7 +41,7 @@ import java.util.List; * The Geocoder class requires a backend service that is not included in * the core android framework. The Geocoder query methods will return an * empty list if there no backend service in the platform. Use the - * isImplemented() method to determine whether a Geocoder implementation + * isPresent() method to determine whether a Geocoder implementation * exists. */ public final class Geocoder { @@ -56,13 +56,13 @@ public final class Geocoder { * connectivity may still cause these methods to return null or * empty lists. */ - public static Boolean isImplemented() { + public static boolean isPresent() { IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE); ILocationManager lm = ILocationManager.Stub.asInterface(b); try { - return lm.geocoderIsImplemented(); + return lm.geocoderIsPresent(); } catch (RemoteException e) { - Log.e(TAG, "isImplemented: got RemoteException", e); + Log.e(TAG, "isPresent: got RemoteException", e); return false; } } diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java index 8b8e63b2c98a..174fe3e0af2e 100644 --- a/location/java/android/location/GeocoderParams.java +++ b/location/java/android/location/GeocoderParams.java @@ -29,6 +29,8 @@ import java.util.Locale; * as well as the Geocoder client's package name for geocoder server * logging. This information is kept in a separate class to allow for * future expansion of the IGeocodeProvider interface. + * + * @hide */ public class GeocoderParams implements Parcelable { private Locale mLocale; diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 32d4b274f00c..2255bf2ecaaa 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -67,7 +67,7 @@ interface ILocationManager // it need not be shared with other providers. void reportLocation(in Location location, boolean passive); - boolean geocoderIsImplemented(); + boolean geocoderIsPresent(); String getFromLocation(double latitude, double longitude, int maxResults, in GeocoderParams params, out List<Address> addrs); String getFromLocationName(String locationName, diff --git a/location/java/android/location/provider/GeocodeProvider.java b/location/java/android/location/provider/GeocodeProvider.java index 9a587631690a..493c631eb693 100644 --- a/location/java/android/location/provider/GeocodeProvider.java +++ b/location/java/android/location/provider/GeocodeProvider.java @@ -29,6 +29,8 @@ import java.util.List; * outside of the core android platform. * Geocode providers can be implemented as services and return the result of * {@link GeocodeProvider#getBinder()} in its getBinder() method. + * + * @hide */ public abstract class GeocodeProvider { diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java index 95b4425bfc25..14dea1482e0f 100644 --- a/location/java/android/location/provider/LocationProvider.java +++ b/location/java/android/location/provider/LocationProvider.java @@ -34,6 +34,8 @@ import android.util.Log; * outside of the core android platform. * Location providers can be implemented as services and return the result of * {@link LocationProvider#getBinder()} in its getBinder() method. + * + * @hide */ public abstract class LocationProvider { diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java index ae67114a27fb..ed7601eb19c4 100644 --- a/media/java/android/media/AudioEffect.java +++ b/media/java/android/media/AudioEffect.java @@ -847,39 +847,40 @@ public class AudioEffect { // ------------------------------------------------------------------------- /** - * This intent launches an audio effect control panel UI. The goal of this intent is to enable - * separate implementations of music/media player applications and audio effect control - * application or services. This will allow platform vendors to offer more advanced control - * options for standard effects or control for platform specific effects. + * Intent to launch an audio effect control panel UI. + * <p>The goal of this intent is to enable separate implementations of music/media player + * applications and audio effect control application or services. + * This will allow platform vendors to offer more advanced control options for standard effects + * or control for platform specific effects. * <p>The intent carries a number of extras used by the player application to communicate * necessary pieces of information to the control panel application. * <p>The calling application must use the * {@link android.app.Activity#startActivityForResult(Intent, int)} method to launch the * control panel so that its package name is indicated and used by the control panel * application to keep track of changes for this particular application. - * <p>The android.media.EXTRA_AUDIO_SESSION extra will indicate an audio session to which the + * <p>The {@link #EXTRA_AUDIO_SESSION} extra will indicate an audio session to which the * audio effects should be applied. If no audio session is specified, either one of the * follownig will happen: - * - If an audio session was previously opened by the calling application with + * <p>- If an audio session was previously opened by the calling application with * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intent, the effect changes will * be applied to that session. - * - If no audio session is opened, the changes will be stored in the package specific storage - * area and applied whenever a new audio session is opened by this application. - * <p>The android.media.EXTRA_CONTENT_TYPE extra will help the control panel application + * <p>- If no audio session is opened, the changes will be stored in the package specific + * storage area and applied whenever a new audio session is opened by this application. + * <p>The {@link #EXTRA_CONTENT_TYPE} extra will help the control panel application * customize both the UI layout and the default audio effect settings if none are already * stored for the calling application. - * {@hide} pending API council approval */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL = "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"; /** - * This intent indicates to the effect control application or service that a new audio session - * is opened and requires audio effects to be applied. This is different from - * {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no UI should be displayed in - * this case. Music player applications can broadcast this intent before starting playback - * to make sure that any audio effect settings previously selected by the user are applied. + * Intent to signal to the effect control application or service that a new audio session + * is opened and requires audio effects to be applied. + * <p>This is different from {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no + * UI should be displayed in this case. Music player applications can broadcast this intent + * before starting playback to make sure that any audio effect settings previously selected + * by the user are applied. * <p>The effect control application receiving this intent will look for previously stored * settings for the calling application, create all required audio effects and apply the * effect settings to the specified audio session. @@ -888,48 +889,50 @@ public class AudioEffect { * <p>If no stored settings are found for the calling application, default settings for the * content type indicated by {@link #EXTRA_CONTENT_TYPE} will be applied. The default settings * for a given content type are platform specific. - * {@hide} pending API council approval */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION = "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"; /** - * This intent indicates to the effect control application or service that an audio session + * Intent to signal to the effect control application or service that an audio session * is closed and that effects should not be applied anymore. - * <p>The effect control application receiving this intent will delete all effects on this - * session and store current settings in package specific storage. + * <p>The effect control application receiving this intent will delete all effects on + * this session and store current settings in package specific storage. * <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the * audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory. * <p>It is good practice for applications to broadcast this intent when music playback stops * and/or when exiting to free system resources consumed by audio effect engines. - * {@hide} pending API council approval */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION = "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"; /** - * This extra indicates the ID of the audio session the effects should be applied to. + * Contains the ID of the audio session the effects should be applied to. + * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL}, + * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and + * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents. * <p>The extra value is of type int and is the audio session ID. - * @see android.media.MediaPlayer#setAudioSessionId(int) for details on audio sessions. - * {@hide} pending API council approval + * + * @see android.media.MediaPlayer#setAudioSessionId(int) */ public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION"; /** - * This extra indicates the package name of the calling application for - * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and + * Contains the package name of the calling application. + * <p>This extra is for use with {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents. * <p>The extra value is a string containing the full package name. - * {@hide} pending API council approval */ public static final String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME"; /** - * This extra indicates which type of content is played by the application. This information is - * used by the effect control application to customize UI and default effect settings. - * The content type is one of the following: + * Indicates which type of content is played by the application. + * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} and + * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intents. + * <p>This information is used by the effect control application to customize UI and select + * appropriate default effect settings. The content type is one of the following: * <ul> * <li>{@link #CONTENT_TYPE_MUSIC}</li> * <li>{@link #CONTENT_TYPE_MOVIE}</li> @@ -937,28 +940,23 @@ public class AudioEffect { * <li>{@link #CONTENT_TYPE_VOICE}</li> * </ul> * If omitted, the content type defaults to {@link #CONTENT_TYPE_MUSIC}. - * {@hide} pending API council approval */ public static final String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE"; /** * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is music - * {@hide} pending API council approval */ public static final int CONTENT_TYPE_MUSIC = 0; /** - * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video of movie - * {@hide} pending API council approval + * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video or movie */ public static final int CONTENT_TYPE_MOVIE = 1; /** * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is game audio - * {@hide} pending API council approval */ public static final int CONTENT_TYPE_GAME = 2; /** * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is voice audio - * {@hide} pending API council approval */ public static final int CONTENT_TYPE_VOICE = 3; diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp index c5b51c054c5d..e4ed5e69b263 100644 --- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp +++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp @@ -123,6 +123,8 @@ status_t AACDecoder::start(MetaData *params) { mAnchorTimeUs = 0; mNumSamplesOutput = 0; mStarted = true; + mNumDecodedBuffers = 0; + mUpsamplingFactor = 2; return OK; } @@ -207,22 +209,65 @@ status_t AACDecoder::read( Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf); - // Check on the sampling rate to see whether it is changed. - int32_t sampleRate; - CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate)); - if (mConfig->samplingRate != sampleRate) { - mMeta->setInt32(kKeySampleRate, mConfig->samplingRate); - LOGW("Sample rate was %d, but now is %d", - sampleRate, mConfig->samplingRate); - buffer->release(); - mInputBuffer->release(); - mInputBuffer = NULL; - return INFO_FORMAT_CHANGED; + /* + * AAC+/eAAC+ streams can be signalled in two ways: either explicitly + * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual + * rate system and the sampling rate in the final output is actually + * doubled compared with the core AAC decoder sampling rate. + * + * Explicit signalling is done by explicitly defining SBR audio object + * type in the bitstream. Implicit signalling is done by embedding + * SBR content in AAC extension payload specific to SBR, and hence + * requires an AAC decoder to perform pre-checks on actual audio frames. + * + * Thus, we could not say for sure whether a stream is + * AAC+/eAAC+ until the first data frame is decoded. + */ + if (++mNumDecodedBuffers <= 2) { + LOGV("audio/extended audio object type: %d + %d", + mConfig->audioObjectType, mConfig->extendedAudioObjectType); + LOGV("aac+ upsampling factor: %d desired channels: %d", + mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels); + + CHECK(mNumDecodedBuffers > 0); + if (mNumDecodedBuffers == 1) { + mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor; + // Check on the sampling rate to see whether it is changed. + int32_t sampleRate; + CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate)); + if (mConfig->samplingRate != sampleRate) { + mMeta->setInt32(kKeySampleRate, mConfig->samplingRate); + LOGW("Sample rate was %d Hz, but now is %d Hz", + sampleRate, mConfig->samplingRate); + buffer->release(); + mInputBuffer->release(); + mInputBuffer = NULL; + return INFO_FORMAT_CHANGED; + } + } else { // mNumDecodedBuffers == 2 + if (mConfig->extendedAudioObjectType == MP4AUDIO_AAC_LC || + mConfig->extendedAudioObjectType == MP4AUDIO_LTP) { + if (mUpsamplingFactor == 2) { + // The stream turns out to be not aacPlus mode anyway + LOGW("Disable AAC+/eAAC+ since extended audio object type is %d", + mConfig->extendedAudioObjectType); + mConfig->aacPlusEnabled = 0; + } + } else { + if (mUpsamplingFactor == 1) { + // aacPlus mode does not buy us anything, but to cause + // 1. CPU load to increase, and + // 2. a half speed of decoding + LOGW("Disable AAC+/eAAC+ since upsampling factor is 1"); + mConfig->aacPlusEnabled = 0; + } + } + } } size_t numOutBytes = mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels; - if (mConfig->aacPlusUpsamplingFactor == 2) { + if (mUpsamplingFactor == 2) { if (mConfig->desiredChannels == 1) { memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2); } diff --git a/media/libstagefright/include/AACDecoder.h b/media/libstagefright/include/AACDecoder.h index 200f93c646b8..886a3b723ebd 100644 --- a/media/libstagefright/include/AACDecoder.h +++ b/media/libstagefright/include/AACDecoder.h @@ -53,6 +53,8 @@ private: int64_t mAnchorTimeUs; int64_t mNumSamplesOutput; status_t mInitCheck; + int64_t mNumDecodedBuffers; + int32_t mUpsamplingFactor; MediaBuffer *mInputBuffer; diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png Binary files differindex d0d13457b112..95866b12e611 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g_fully.png Binary files differindex 5af2b050cb9e..5524e26ac7eb 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g_fully.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g_fully.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png Binary files differindex 11ee0f289511..07ea499fb741 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g_fully.png Binary files differindex 31c976a0d6cc..a8411fc6b552 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g_fully.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g_fully.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png Binary files differindex dba9675cd963..95bb3cd92510 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g_fully.png Binary files differindex 3903545edde0..f7dda73f14b2 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g_fully.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g_fully.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png Binary files differindex 04ec59e36d32..cac78027f574 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g_fully.png Binary files differindex d44a4cfc1177..eb5150fac33d 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g_fully.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g_fully.png diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java index 7ccf210f77be..0fc092ef9a09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java @@ -711,21 +711,20 @@ public class StatusBarPolicy { ConnectivityManager.EXTRA_NETWORK_INFO)); int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0); Slog.d(TAG, "got CONNECTIVITY_ACTION - info=" + info + ", status = " + connectionStatus); - if (info.isConnected() == false) return; + + int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0); switch (info.getType()) { case ConnectivityManager.TYPE_MOBILE: - if (info.isConnected()) { - updateDataNetType(info.getSubtype(), connectionStatus); - updateDataIcon(); - updateSignalStrength(); // apply any change in connectionStatus - } + mInetCondition = inetCondition; + updateDataNetType(info.getSubtype()); + updateDataIcon(); + updateSignalStrength(); // apply any change in connectionStatus break; case ConnectivityManager.TYPE_WIFI: + mInetCondition = inetCondition; if (info.isConnected()) { mIsWifiConnected = true; - mInetCondition = - (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0); int iconId; if (mLastWifiSignalLevel == -1) { iconId = sWifiSignalImages[mInetCondition][0]; @@ -738,7 +737,6 @@ public class StatusBarPolicy { } else { mLastWifiSignalLevel = -1; mIsWifiConnected = false; - mInetCondition = 0; int iconId = sWifiSignalImages[0][0]; mService.setIcon("wifi", iconId, 0); @@ -777,9 +775,8 @@ public class StatusBarPolicy { @Override public void onDataConnectionStateChanged(int state, int networkType) { mDataState = state; - updateDataNetType(networkType, 0); + updateDataNetType(networkType); updateDataIcon(); - updateSignalStrength(); // apply the change in connection status } @Override @@ -940,8 +937,7 @@ public class StatusBarPolicy { return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr; } - private final void updateDataNetType(int net, int inetCondition) { - mInetCondition = (inetCondition > INET_CONDITION_THRESHOLD ? 1 : 0); + private final void updateDataNetType(int net) { switch (net) { case TelephonyManager.NETWORK_TYPE_EDGE: mDataIconList = sDataNetType_e[mInetCondition]; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java index af736aa33195..b5552770b656 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java @@ -82,7 +82,7 @@ import com.android.systemui.statusbar.policy.StatusBarPolicy; public class StatusBarService extends Service implements CommandQueue.Callbacks { static final String TAG = "StatusBarService"; - static final boolean SPEW = false; + static final boolean SPEW = true; public static final String ACTION_STATUSBAR_START = "com.android.internal.policy.statusbar.START"; @@ -1534,4 +1534,3 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks } }; } - diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java index 55d31ec00e80..29df28eb1045 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java @@ -30,6 +30,7 @@ import android.content.DialogInterface.OnCancelListener; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.hardware.Usb; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -70,11 +71,11 @@ public class UsbStorageActivity extends Activity static final boolean localLOGV = false; /** Used to detect when the USB cable is unplugged, so we can call finish() */ - private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { + private BroadcastReceiver mUsbStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction() == Intent.ACTION_BATTERY_CHANGED) { - handleBatteryChanged(intent); + if (intent.getAction().equals(Usb.ACTION_USB_STATE)) { + handleUsbStateChanged(intent); } } }; @@ -139,7 +140,7 @@ public class UsbStorageActivity extends Activity super.onResume(); mStorageManager.registerListener(mStorageListener); - registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + registerReceiver(mUsbStateReceiver, new IntentFilter(Usb.ACTION_USB_STATE)); try { switchDisplay(mStorageManager.isUsbMassStorageEnabled()); } catch (Exception ex) { @@ -151,15 +152,15 @@ public class UsbStorageActivity extends Activity protected void onPause() { super.onPause(); - unregisterReceiver(mBatteryReceiver); + unregisterReceiver(mUsbStateReceiver); if (mStorageManager == null && mStorageListener != null) { mStorageManager.unregisterListener(mStorageListener); } } - private void handleBatteryChanged(Intent intent) { - int pluggedType = intent.getIntExtra("plugged", 0); - if (pluggedType == 0) { + private void handleUsbStateChanged(Intent intent) { + boolean connected = intent.getExtras().getBoolean(Usb.USB_CONNECTED); + if (!connected) { // It was disconnected from the plug, so finish finish(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index c5505d1139a0..f38748b44e83 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -48,6 +48,7 @@ import com.android.server.connectivity.Tethering; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.GregorianCalendar; import java.util.List; /** @@ -109,6 +110,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean mSystemReady; private Intent mInitialBroadcast; + // used in DBG mode to track inet condition reports + private static final int INET_CONDITION_LOG_MAX_SIZE = 15; + private ArrayList mInetLog; + private static class NetworkAttributes { /** * Class for holding settings read from resources. @@ -329,6 +334,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mTethering.getTetherableWifiRegexs().length != 0) && mTethering.getUpstreamIfaceRegexs().length != 0); + if (DBG) { + mInetLog = new ArrayList(); + } } @@ -912,11 +920,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { newNet = tryFailover(prevNetType); if (newNet != null) { NetworkInfo switchTo = newNet.getNetworkInfo(); + if (!switchTo.isConnected()) { + // if the other net is connected they've already reset this and perhaps even gotten + // a positive report we don't want to overwrite, but if not we need to clear this now + // to turn our cellular sig strength white + mDefaultInetConditionPublished = 0; + } intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { + mDefaultInetConditionPublished = 0; // we're not connected anymore intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); } } + intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); // do this before we broadcast the change handleConnectivityChange(prevNetType); @@ -1075,12 +1091,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { newNet = tryFailover(info.getType()); if (newNet != null) { NetworkInfo switchTo = newNet.getNetworkInfo(); + if (!switchTo.isConnected()) { + // if the other net is connected they've already reset this and perhaps even gotten + // a positive report we don't want to overwrite, but if not we need to clear this now + // to turn our cellular sig strength white + mDefaultInetConditionPublished = 0; + } intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { + mDefaultInetConditionPublished = 0; intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); } } + intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); sendStickyBroadcast(intent); /* * If the failover network is already connected, then immediately send @@ -1365,6 +1389,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { pw.println(); mTethering.dump(fd, pw, args); + + if (mInetLog != null) { + pw.println(); + pw.println("Inet condition reports:"); + for(int i = 0; i < mInetLog.size(); i++) { + pw.println(mInetLog.get(i)); + } + } } // must be stateless - things change under us. @@ -1613,6 +1645,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { android.Manifest.permission.STATUS_BAR, "ConnectivityService"); + if (DBG) { + int pid = getCallingPid(); + int uid = getCallingUid(); + String s = pid + "(" + uid + ") reports inet is " + + (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " + + "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime(); + mInetLog.add(s); + while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) { + mInetLog.remove(0); + } + } mHandler.sendMessage(mHandler.obtainMessage( NetworkStateTracker.EVENT_INET_CONDITION_CHANGE, networkType, percentage)); } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index f3ce8baaf785..643b2f52ff73 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -1959,7 +1959,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // Geocoder - public boolean geocoderIsImplemented() { + public boolean geocoderIsPresent() { return mGeocodeProvider != null; } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 72784d50c423..4c15c940eff7 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -222,6 +222,9 @@ class PackageManagerService extends IPackageManager.Stub { // This is the object monitoring the system app dir. final FileObserver mSystemInstallObserver; + // This is the object monitoring the system app dir. + final FileObserver mVendorInstallObserver; + // This is the object monitoring mAppInstallDir. final FileObserver mAppInstallObserver; @@ -234,6 +237,7 @@ class PackageManagerService extends IPackageManager.Stub { final File mFrameworkDir; final File mSystemAppDir; + final File mVendorAppDir; final File mAppInstallDir; final File mDalvikCacheDir; @@ -927,6 +931,14 @@ class PackageManagerService extends IPackageManager.Stub { scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode); + // Collect all vendor packages. + mVendorAppDir = new File("/vendor/app"); + mVendorInstallObserver = new AppDirObserver( + mVendorAppDir.getPath(), OBSERVER_EVENTS, true); + mVendorInstallObserver.startWatching(); + scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM + | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode); + if (mInstaller != null) { if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands"); mInstaller.moveFiles(); @@ -2493,9 +2505,13 @@ class PackageManagerService extends IPackageManager.Stub { } private void scanDirLI(File dir, int flags, int scanMode) { - Log.d(TAG, "Scanning app dir " + dir); - String[] files = dir.list(); + if (files == null) { + Log.d(TAG, "No files in app dir " + dir); + return; + } + + Log.d(TAG, "Scanning app dir " + dir); int i; for (i=0; i<files.length; i++) { diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 371f22ee085e..c047e1052962 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -145,7 +145,7 @@ public class WifiService extends IWifiManager.Stub { */ private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */ - private static final String WAKELOCK_TAG = "WifiService"; + private static final String WAKELOCK_TAG = "*wifi*"; /** * The maximum amount of time to hold the wake lock after a disconnect @@ -173,6 +173,7 @@ public class WifiService extends IWifiManager.Stub { private static final int MESSAGE_STOP_ACCESS_POINT = 7; private static final int MESSAGE_SET_CHANNELS = 8; private static final int MESSAGE_ENABLE_NETWORKS = 9; + private static final int MESSAGE_START_SCAN = 10; private final WifiHandler mWifiHandler; @@ -385,23 +386,12 @@ public class WifiService extends IWifiManager.Stub { /** * see {@link android.net.wifi.WifiManager#startScan()} - * @return {@code true} if the operation succeeds */ - public boolean startScan(boolean forceActive) { + public void startScan(boolean forceActive) { enforceChangePermission(); + if (mWifiHandler == null) return; - switch (mWifiStateTracker.getSupplicantState()) { - case DISCONNECTED: - case INACTIVE: - case SCANNING: - case DORMANT: - break; - default: - mWifiStateTracker.setScanResultHandling( - WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY); - break; - } - return mWifiStateTracker.scan(forceActive); + Message.obtain(mWifiHandler, MESSAGE_START_SCAN, forceActive ? 1 : 0, 0).sendToTarget(); } /** @@ -1825,6 +1815,7 @@ public class WifiService extends IWifiManager.Stub { } } mWifiStateTracker.updateBatteryWorkSourceLocked(mTmpWorkSource); + sWakeLock.setWorkSource(mTmpWorkSource); } } @@ -2000,6 +1991,21 @@ public class WifiService extends IWifiManager.Stub { mWifiStateTracker.enableAllNetworks(getConfiguredNetworks()); break; + case MESSAGE_START_SCAN: + boolean forceActive = (msg.arg1 == 1); + switch (mWifiStateTracker.getSupplicantState()) { + case DISCONNECTED: + case INACTIVE: + case SCANNING: + case DORMANT: + break; + default: + mWifiStateTracker.setScanResultHandling( + WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY); + break; + } + mWifiStateTracker.scan(forceActive); + break; } } } diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 9835098baa78..d7a1ac25223a 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -8316,6 +8316,11 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mDisplay == null) { + // Not yet initialized, nothing to do. + return; + } + boolean recoveringMemory = false; if (mForceRemoves != null) { recoveringMemory = true; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index cf767ca878cf..4f0d2d56499b 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -561,6 +561,11 @@ public final class ActivityManagerService extends ActivityManagerNative BroadcastRecord mPendingBroadcast = null; /** + * The receiver index that is pending, to restart the broadcast if needed. + */ + int mPendingBroadcastRecvIndex; + + /** * Keeps track of all IIntentReceivers that have been registered for * broadcasts. Hash keys are the receiver IBinder, hash value is * a ReceiverList. @@ -747,6 +752,7 @@ public final class ActivityManagerService extends ActivityManagerNative ComponentName mTopComponent; String mTopAction; String mTopData; + boolean mProcessesReady = false; boolean mSystemReady = false; boolean mBooting = false; boolean mWaitingUpdate = false; @@ -964,7 +970,11 @@ public final class ActivityManagerService extends ActivityManagerNative return; } - broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"), + Intent intent = new Intent("android.intent.action.ANR"); + if (!mProcessesReady) { + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } + broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, false, false, MY_PID, Process.SYSTEM_UID); @@ -1051,7 +1061,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Only process broadcast timeouts if the system is ready. That way // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended // to do heavy lifting for system up - if (mSystemReady) { + if (mProcessesReady) { broadcastTimeout(); } } break; @@ -1383,7 +1393,7 @@ public final class ActivityManagerService extends ActivityManagerNative mBatteryStatsService = new BatteryStatsService(new File( systemDir, "batterystats.bin").toString()); mBatteryStatsService.getActiveStatistics().readLocked(); - mBatteryStatsService.getActiveStatistics().writeLocked(); + mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); mOnBattery = mBatteryStatsService.getActiveStatistics().getIsOnBattery(); mBatteryStatsService.getActiveStatistics().setCallback(this); @@ -1536,7 +1546,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (mLastWriteTime < (now-BATTERY_STATS_TIME)) { mLastWriteTime = now; - mBatteryStatsService.getActiveStatistics().writeLocked(); + mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); } } } @@ -1717,10 +1727,12 @@ public final class ActivityManagerService extends ActivityManagerNative if (!knownToBeDead || app.thread == null) { // We already have the app running, or are waiting for it to // come up (we have a pid but not yet its thread), so keep it. + if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app); return app; } else { // An application record is attached to a previous process, // clean it up now. + if (DEBUG_PROCESSES) Slog.v(TAG, "App died: " + app); handleAppDiedLocked(app, true); } } @@ -1732,6 +1744,8 @@ public final class ActivityManagerService extends ActivityManagerNative // If we are in the background, then check to see if this process // is bad. If so, we will just silently fail. if (mBadProcesses.get(info.processName, info.uid) != null) { + if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid + + "/" + info.processName); return null; } } else { @@ -1739,6 +1753,8 @@ public final class ActivityManagerService extends ActivityManagerNative // crash count so that we won't make it bad until they see at // least one crash dialog again, and make the process good again // if it had been bad. + if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid + + "/" + info.processName); mProcessCrashTimes.remove(info.processName, info.uid); if (mBadProcesses.get(info.processName, info.uid) != null) { EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid, @@ -1760,12 +1776,13 @@ public final class ActivityManagerService extends ActivityManagerNative // If the system is not ready yet, then hold off on starting this // process until it is. - if (!mSystemReady + if (!mProcessesReady && !isAllowedWhileBooting(info) && !allowWhileBooting) { if (!mProcessesOnHold.contains(app)) { mProcessesOnHold.add(app); } + if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app); return app; } @@ -1787,6 +1804,8 @@ public final class ActivityManagerService extends ActivityManagerNative app.pid = 0; } + if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, + "startProcessLocked removing on hold: " + app); mProcessesOnHold.remove(app); updateCpuStats(); @@ -3040,11 +3059,8 @@ public final class ActivityManagerService extends ActivityManagerNative Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED, Uri.fromParts("package", packageName, null)); intent.putExtra(Intent.EXTRA_UID, pkgUid); - synchronized (this) { - broadcastIntentLocked(null, null, intent, - null, null, 0, null, null, null, - false, false, MY_PID, Process.SYSTEM_UID); - } + broadcastIntentInPackage("android", Process.SYSTEM_UID, intent, + null, null, 0, null, null, null, false, false); } catch (RemoteException e) { } } finally { @@ -3148,6 +3164,7 @@ public final class ActivityManagerService extends ActivityManagerNative public void closeSystemDialogs(String reason) { Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); if (reason != null) { intent.putExtra("reason", reason); } @@ -3225,6 +3242,9 @@ public final class ActivityManagerService extends ActivityManagerNative forceStopPackageLocked(packageName, uid, false, false, true); Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, Uri.fromParts("package", packageName, null)); + if (!mProcessesReady) { + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } intent.putExtra(Intent.EXTRA_UID, uid); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, @@ -3427,6 +3447,8 @@ public final class ActivityManagerService extends ActivityManagerNative } if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) { Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping"); + mPendingBroadcast.state = BroadcastRecord.IDLE; + mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; scheduleBroadcastsLocked(); } @@ -3502,7 +3524,7 @@ public final class ActivityManagerService extends ActivityManagerNative mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); - boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info); + boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); List providers = normalMode ? generateApplicationProvidersLocked(app) : null; if (!normalMode) { @@ -3561,6 +3583,8 @@ public final class ActivityManagerService extends ActivityManagerNative // Remove this record from the list of starting applications. mPersistentStartingProcesses.remove(app); + if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, + "Attach application locked removing on hold: " + app); mProcessesOnHold.remove(app); boolean badApp = false; @@ -3702,7 +3726,9 @@ public final class ActivityManagerService extends ActivityManagerNative ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(mProcessesOnHold); for (int ip=0; ip<NP; ip++) { - this.startProcessLocked(procs.get(ip), "on-hold", null); + if (DEBUG_PROCESSES) Slog.v(TAG, "Starting process on hold: " + + procs.get(ip)); + startProcessLocked(procs.get(ip), "on-hold", null); } } @@ -5253,7 +5279,7 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException(msg); } - if (!mSystemReady && !mDidUpdate && !mWaitingUpdate + if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate && !cpi.processName.equals("system")) { // If this content provider does not run in the system // process, and the system is not yet ready to run other @@ -6040,6 +6066,11 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "Removing system update proc: " + proc); removeProcessLocked(proc, true); } + + // Now that we have cleaned up any update processes, we + // are ready to start launching real processes and know that + // we won't trample on them any more. + mProcessesReady = true; } } @@ -7283,8 +7314,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (dumpAll) { pw.println(" Total persistent processes: " + numPers); pw.println(" mStartRunning=" + mStartRunning - + " mSystemReady=" + mSystemReady - + " mBooting=" + mBooting + + " mProcessesReady=" + mProcessesReady + + " mSystemReady=" + mSystemReady); + pw.println(" mBooting=" + mBooting + " mBooted=" + mBooted + " mFactoryTest=" + mFactoryTest); pw.println(" mGoingToSleep=" + mMainStack.mGoingToSleep); @@ -8098,6 +8130,8 @@ public final class ActivityManagerService extends ActivityManagerNative restart = true; } } + if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, + "Clean-up removing on hold: " + app); mProcessesOnHold.remove(app); if (app == mHomeProcess) { @@ -10118,7 +10152,7 @@ public final class ActivityManagerService extends ActivityManagerNative } boolean replaced = false; if (replacePending) { - for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) { + for (int i=mOrderedBroadcasts.size()-1; i>0; i--) { if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) { if (DEBUG_BROADCAST) Slog.v(TAG, "***** DROPPING ORDERED: " + intent); @@ -10137,35 +10171,41 @@ public final class ActivityManagerService extends ActivityManagerNative return BROADCAST_SUCCESS; } - public final int broadcastIntent(IApplicationThread caller, - Intent intent, String resolvedType, IIntentReceiver resultTo, - int resultCode, String resultData, Bundle map, - String requiredPermission, boolean serialized, boolean sticky) { + final Intent verifyBroadcastLocked(Intent intent) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } - synchronized(this) { - int flags = intent.getFlags(); - - if (!mSystemReady) { - // if the caller really truly claims to know what they're doing, go - // ahead and allow the broadcast without launching any receivers - if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { - intent = new Intent(intent); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){ - Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent - + " before boot completion"); - throw new IllegalStateException("Cannot broadcast before boot completed"); - } - } - - if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { - throw new IllegalArgumentException( - "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); + int flags = intent.getFlags(); + + if (!mProcessesReady) { + // if the caller really truly claims to know what they're doing, go + // ahead and allow the broadcast without launching any receivers + if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { + intent = new Intent(intent); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { + Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent + + " before boot completion"); + throw new IllegalStateException("Cannot broadcast before boot completed"); } + } + + if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { + throw new IllegalArgumentException( + "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); + } + + return intent; + } + + public final int broadcastIntent(IApplicationThread caller, + Intent intent, String resolvedType, IIntentReceiver resultTo, + int resultCode, String resultData, Bundle map, + String requiredPermission, boolean serialized, boolean sticky) { + synchronized(this) { + intent = verifyBroadcastLocked(intent); final ProcessRecord callerApp = getRecordForAppLocked(caller); final int callingPid = Binder.getCallingPid(); @@ -10186,6 +10226,8 @@ public final class ActivityManagerService extends ActivityManagerNative int resultCode, String resultData, Bundle map, String requiredPermission, boolean serialized, boolean sticky) { synchronized(this) { + intent = verifyBroadcastLocked(intent); + final long origId = Binder.clearCallingIdentity(); int res = broadcastIntentLocked(null, packageName, intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermission, @@ -10399,6 +10441,8 @@ public final class ActivityManagerService extends ActivityManagerNative private final void processCurBroadcastLocked(BroadcastRecord r, ProcessRecord app) throws RemoteException { + if (DEBUG_BROADCAST) Slog.v(TAG, + "Process cur broadcast " + r + " for app " + app); if (app.thread == null) { throw new RemoteException(); } @@ -10418,9 +10462,13 @@ public final class ActivityManagerService extends ActivityManagerNative ensurePackageDexOpt(r.intent.getComponent().getPackageName()); app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver, r.resultCode, r.resultData, r.resultExtras, r.ordered); + if (DEBUG_BROADCAST) Slog.v(TAG, + "Process cur broadcast " + r + " DELIVERED for app " + app); started = true; } finally { if (!started) { + if (DEBUG_BROADCAST) Slog.v(TAG, + "Process cur broadcast " + r + ": NOT STARTED!"); r.receiver = null; r.curApp = null; app.curReceiver = null; @@ -10585,6 +10633,8 @@ public final class ActivityManagerService extends ActivityManagerNative } else { Slog.w(TAG, "pending app " + mPendingBroadcast.curApp + " died before responding to broadcast"); + mPendingBroadcast.state = BroadcastRecord.IDLE; + mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; } } @@ -10615,7 +10665,7 @@ public final class ActivityManagerService extends ActivityManagerNative // one time heavy lifting after system upgrades and can take // significant amounts of time. int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; - if (mSystemReady && r.dispatchTime > 0) { + if (mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) { @@ -10686,7 +10736,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast " + r); if (DEBUG_BROADCAST) Slog.v(TAG, - "Submitting BROADCAST_TIMEOUT_MSG for " + "Submitting BROADCAST_TIMEOUT_MSG for " + r + " at " + (r.receiverTime + BROADCAST_TIMEOUT)); Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG); mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT); @@ -10754,10 +10804,15 @@ public final class ActivityManagerService extends ActivityManagerNative } if (r.curApp != null && r.curApp.crashing) { // If the target process is crashing, just skip it. + if (DEBUG_BROADCAST) Slog.v(TAG, + "Skipping deliver ordered " + r + " to " + r.curApp + + ": process crashing"); skip = true; } if (skip) { + if (DEBUG_BROADCAST) Slog.v(TAG, + "Skipping delivery of ordered " + r + " for whatever reason"); r.receiver = null; r.curFilter = null; r.state = BroadcastRecord.IDLE; @@ -10789,6 +10844,8 @@ public final class ActivityManagerService extends ActivityManagerNative } // Not running -- get it started, to be executed when the app comes up. + if (DEBUG_BROADCAST) Slog.v(TAG, + "Need to start app " + targetProcess + " for broadcast " + r); if ((r.curApp=startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, @@ -10810,6 +10867,7 @@ public final class ActivityManagerService extends ActivityManagerNative } mPendingBroadcast = r; + mPendingBroadcastRecvIndex = recIdx; } } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 4fc802003312..a4497d64e28a 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -1104,26 +1104,30 @@ public class ActivityStack { // Okay we are now going to start a switch, to 'next'. We may first // have to pause the current activity, but this is an important point // where we have decided to go to 'next' so keep track of that. - if (mLastStartedActivity != null && !mLastStartedActivity.finishing) { - long now = SystemClock.uptimeMillis(); - final boolean inTime = mLastStartedActivity.startTime != 0 - && (mLastStartedActivity.startTime + START_WARN_TIME) >= now; - final int lastUid = mLastStartedActivity.info.applicationInfo.uid; - final int nextUid = next.info.applicationInfo.uid; - if (inTime && lastUid != nextUid - && lastUid != next.launchedFromUid - && mService.checkPermission( - android.Manifest.permission.STOP_APP_SWITCHES, - -1, next.launchedFromUid) - != PackageManager.PERMISSION_GRANTED) { - mService.showLaunchWarningLocked(mLastStartedActivity, next); + // XXX "App Redirected" dialog is getting too many false positives + // at this point, so turn off for now. + if (false) { + if (mLastStartedActivity != null && !mLastStartedActivity.finishing) { + long now = SystemClock.uptimeMillis(); + final boolean inTime = mLastStartedActivity.startTime != 0 + && (mLastStartedActivity.startTime + START_WARN_TIME) >= now; + final int lastUid = mLastStartedActivity.info.applicationInfo.uid; + final int nextUid = next.info.applicationInfo.uid; + if (inTime && lastUid != nextUid + && lastUid != next.launchedFromUid + && mService.checkPermission( + android.Manifest.permission.STOP_APP_SWITCHES, + -1, next.launchedFromUid) + != PackageManager.PERMISSION_GRANTED) { + mService.showLaunchWarningLocked(mLastStartedActivity, next); + } else { + next.startTime = now; + mLastStartedActivity = next; + } } else { - next.startTime = now; + next.startTime = SystemClock.uptimeMillis(); mLastStartedActivity = next; } - } else { - next.startTime = SystemClock.uptimeMillis(); - mLastStartedActivity = next; } // We need to start pausing the current activity so the top one diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java index 4d8cbf037ab5..23cb42a3cc49 100644 --- a/telephony/java/com/android/internal/telephony/CallManager.java +++ b/telephony/java/com/android/internal/telephony/CallManager.java @@ -82,7 +82,7 @@ public final class CallManager { // Singleton instance private static final CallManager INSTANCE = new CallManager(); - // list of registered phones + // list of registered phones, which are PhoneBase objs private final ArrayList<Phone> mPhones; // list of supported ringing calls @@ -97,7 +97,7 @@ public final class CallManager { // empty connection list private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>(); - // default phone as the first phone registered + // default phone as the first phone registered, which is PhoneBase obj private Phone mDefaultPhone; // state registrants @@ -181,6 +181,46 @@ public final class CallManager { } /** + * Get the corresponding PhoneBase obj + * + * @param phone a Phone object + * @return the corresponding PhoneBase obj in Phone if Phone + * is a PhoneProxy obj + * or the Phone itself if Phone is not a PhoneProxy obj + */ + private static Phone getPhoneBase(Phone phone) { + if (phone instanceof PhoneProxy) { + return phone.getForegroundCall().getPhone(); + } + return phone; + } + + /** + * Check if two phones refer to the same PhoneBase obj + * + * Note: PhoneBase, not PhoneProxy, is to be used inside of CallManager + * + * Both PhoneBase and PhoneProxy implement Phone interface, so + * they have same phone APIs, such as dial(). The real implementation, for + * example in GSM, is in GSMPhone as extend from PhoneBase, so that + * foregroundCall.getPhone() returns GSMPhone obj. On the other hand, + * PhoneFactory.getDefaultPhone() returns PhoneProxy obj, which has a class + * member of GSMPhone. + * + * So for phone returned by PhoneFacotry, which is used by PhoneApp, + * phone.getForegroundCall().getPhone() != phone + * but + * isSamePhone(phone, phone.getForegroundCall().getPhone()) == true + * + * @param p1 is the first Phone obj + * @param p2 is the second Phone obj + * @return true if p1 and p2 refer to the same phone + */ + public static boolean isSamePhone(Phone p1, Phone p2) { + return (getPhoneBase(p1) == getPhoneBase(p2)); + } + + /** * Returns all the registered phone objects. * @return all the registered phone objects. */ @@ -198,9 +238,7 @@ public final class CallManager { Phone.State s = Phone.State.IDLE; for (Phone phone : mPhones) { - if (phone.getState() == Phone.State.ANSWERING) { - return Phone.State.ANSWERING; - } else if (phone.getState() == Phone.State.RINGING) { + if (phone.getState() == Phone.State.RINGING) { s = Phone.State.RINGING; } else if (phone.getState() == Phone.State.OFFHOOK) { if (s == Phone.State.IDLE) s = Phone.State.OFFHOOK; @@ -246,25 +284,50 @@ public final class CallManager { /** * Register phone to CallManager - * @param phone + * @param phone to be registered * @return true if register successfully */ public boolean registerPhone(Phone phone) { - if (phone != null && !mPhones.contains(phone)) { + Phone basePhone = getPhoneBase(phone); + + if (basePhone != null && !mPhones.contains(basePhone)) { if (mPhones.isEmpty()) { - mDefaultPhone = phone; + mDefaultPhone = basePhone; } - mPhones.add(phone); - mRingingCalls.add(phone.getRingingCall()); - mBackgroundCalls.add(phone.getBackgroundCall()); - mForegroundCalls.add(phone.getForegroundCall()); - registerForPhoneStates(phone); + mPhones.add(basePhone); + mRingingCalls.add(basePhone.getRingingCall()); + mBackgroundCalls.add(basePhone.getBackgroundCall()); + mForegroundCalls.add(basePhone.getForegroundCall()); + registerForPhoneStates(basePhone); return true; } return false; } /** + * unregister phone from CallManager + * @param phone to be unregistered + */ + public void unregisterPhone(Phone phone) { + Phone basePhone = getPhoneBase(phone); + + if (basePhone != null && mPhones.contains(basePhone)) { + mPhones.remove(basePhone); + mRingingCalls.remove(basePhone.getRingingCall()); + mBackgroundCalls.remove(basePhone.getBackgroundCall()); + mForegroundCalls.remove(basePhone.getForegroundCall()); + unregisterForPhoneStates(basePhone); + if (basePhone == mDefaultPhone) { + if (mPhones.isEmpty()) { + mDefaultPhone = null; + } else { + mDefaultPhone = mPhones.get(0); + } + } + } + } + + /** * return the default phone or null if no phone available */ public Phone getDefaultPhone() { @@ -292,39 +355,6 @@ public final class CallManager { return getFirstActiveRingingCall().getPhone(); } - /** - * @return the first answering call - */ - public Call getFirstAnsweringCall() { - for (Phone phone : mPhones) { - if (phone.getState() == Phone.State.ANSWERING) { - return phone.getForegroundCall(); - } - } - return null; - } - - /** - * unregister phone from CallManager - * @param phone - */ - public void unregisterPhone(Phone phone) { - if (phone != null && mPhones.contains(phone)) { - mPhones.remove(phone); - mRingingCalls.remove(phone.getRingingCall()); - mBackgroundCalls.remove(phone.getBackgroundCall()); - mForegroundCalls.remove(phone.getForegroundCall()); - unregisterForPhoneStates(phone); - if (phone == mDefaultPhone) { - if (mPhones.isEmpty()) { - mDefaultPhone = null; - } else { - mDefaultPhone = mPhones.get(0); - } - } - } - } - public void setAudioMode() { Context context = getContext(); if (context == null) return; @@ -592,8 +622,9 @@ public final class CallManager { * handled asynchronously. */ public Connection dial(Phone phone, String dialString) throws CallStateException { + Phone basePhone = getPhoneBase(phone); if (VDBG) { - Log.d(LOG_TAG, "CallManager.dial( phone=" + phone + ", dialString="+ dialString + ")"); + Log.d(LOG_TAG, "CallManager.dial( phone=" + basePhone + ", dialString="+ dialString + ")"); Log.d(LOG_TAG, this.toString()); } if ( hasActiveFgCall() ) { @@ -601,10 +632,10 @@ public final class CallManager { boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle()); if (DBG) { - Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == phone)); + Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone)); } - if (activePhone != phone) { + if (activePhone != basePhone) { if (hasBgCall) { Log.d(LOG_TAG, "Hangup"); getActiveFgCall().hangup(); @@ -614,7 +645,7 @@ public final class CallManager { } } } - return phone.dial(dialString); + return basePhone.dial(dialString); } /** @@ -1312,7 +1343,7 @@ public final class CallManager { */ public Call getFirstActiveBgCall() { for (Call call : mBackgroundCalls) { - if (!call.isIdle()) { + if (call.getState() != Call.State.IDLE) { return call; } } diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 7464cc74ac3b..9afade33b006 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -55,12 +55,10 @@ public interface Phone { * <li>OFFHOOK = The phone is off hook. At least one call * exists that is dialing, active or holding and no calls are * ringing or waiting.</li> - * <li>ANSWERING = The incoming call is picked up but the - * call is not established yet.</li> * </ul> */ enum State { - IDLE, RINGING, OFFHOOK, ANSWERING; + IDLE, RINGING, OFFHOOK; }; /** diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index 0a87ddbc3bac..35aa3b383a58 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -143,23 +143,15 @@ public class SipPhone extends SipPhoneBase { // in case the active/holding call disappeared and this // is no longer call waiting - if (ringingCall.getState() == Call.State.INCOMING) { + if ((ringingCall.getState() == Call.State.INCOMING) || + (ringingCall.getState() == Call.State.WAITING)) { Log.v(LOG_TAG, "acceptCall"); // Always unmute when answering a new call setMute(false); - // make ringingCall foreground - foregroundCall.switchWith(ringingCall); - foregroundCall.acceptCall(); - } else if (ringingCall.getState() == Call.State.WAITING) { - setMute(false); - switchHoldingAndActive(); - // make ringingCall foreground - foregroundCall.switchWith(ringingCall); - foregroundCall.acceptCall(); + ringingCall.acceptCall(); } else { throw new CallStateException("phone not ringing"); } - updatePhoneState(); } } @@ -482,8 +474,8 @@ public class SipPhone extends SipPhoneBase { } void acceptCall() throws CallStateException { - if (this != foregroundCall) { - throw new CallStateException("acceptCall() in a non-fg call"); + if (this != ringingCall) { + throw new CallStateException("acceptCall() in a non-ringing call"); } if (connections.size() != 1) { throw new CallStateException("acceptCall() in a conf call"); @@ -646,6 +638,18 @@ public class SipPhone extends SipPhoneBase { if (newState == Call.State.INCOMING) { setState(mOwner.getState()); // INCOMING or WAITING } else { + if (mOwner == ringingCall) { + if (ringingCall.getState() == Call.State.WAITING) { + try { + switchHoldingAndActive(); + } catch (CallStateException e) { + // disconnect the call. + onCallEnded(DisconnectCause.LOCAL); + return; + } + } + foregroundCall.switchWith(ringingCall); + } if (newState == Call.State.ACTIVE) call.startAudio(); setState(newState); } diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java index 2efbd175bc0e..9098e6ffb154 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java @@ -538,8 +538,6 @@ abstract class SipPhoneBase extends PhoneBase { if (getRingingCall().isRinging()) { state = State.RINGING; - } else if (getForegroundCall().isRinging()) { - state = State.ANSWERING; } else if (getForegroundCall().isIdle() && getBackgroundCall().isIdle()) { state = State.IDLE; diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 0ee559e7c228..198b1e6b44d6 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -42,7 +42,7 @@ interface IWifiManager boolean pingSupplicant(); - boolean startScan(boolean forceActive); + void startScan(boolean forceActive); List<ScanResult> getScanResults(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index dd162f212cbd..f8835881347a 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -570,7 +570,8 @@ public class WifiManager { */ public boolean startScan() { try { - return mService.startScan(false); + mService.startScan(false); + return true; } catch (RemoteException e) { return false; } @@ -588,7 +589,8 @@ public class WifiManager { */ public boolean startScanActive() { try { - return mService.startScan(true); + mService.startScan(true); + return true; } catch (RemoteException e) { return false; } |