diff options
54 files changed, 601 insertions, 124 deletions
diff --git a/api/current.xml b/api/current.xml index e6df68759a79..1d6feb5d6ff3 100644 --- a/api/current.xml +++ b/api/current.xml @@ -84729,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" @@ -84740,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" @@ -84888,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" 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/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/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/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 871a04413f6e..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. */ 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/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/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/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/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/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/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 87329e3156ad..c047e1052962 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -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(); } /** @@ -2001,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/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; } |