summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt16
-rw-r--r--cmds/installd/commands.c23
-rw-r--r--cmds/installd/installd.h5
-rw-r--r--cmds/installd/tests/installd_utils_test.cpp56
-rw-r--r--cmds/installd/utils.c18
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java33
-rw-r--r--core/java/android/accessibilityservice/IEventListener.aidl2
-rw-r--r--core/java/android/app/ActivityThread.java8
-rw-r--r--core/java/android/app/ApplicationPackageManager.java37
-rw-r--r--core/java/android/app/DatePickerDialog.java7
-rw-r--r--core/java/android/app/TimePickerDialog.java8
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java4
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java26
-rw-r--r--core/java/android/bluetooth/BluetoothDeviceProfileState.java28
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java1
-rw-r--r--core/java/android/bluetooth/BluetoothHealth.java4
-rw-r--r--core/java/android/bluetooth/BluetoothInputDevice.java4
-rw-r--r--core/java/android/bluetooth/BluetoothPan.java6
-rw-r--r--core/java/android/bluetooth/BluetoothPbap.java3
-rw-r--r--core/java/android/content/Intent.java68
-rw-r--r--core/java/android/inputmethodservice/ExtractEditText.java23
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java26
-rw-r--r--core/java/android/os/IBinder.java13
-rw-r--r--core/java/android/provider/MediaStore.java5
-rw-r--r--core/java/android/provider/Settings.java22
-rwxr-xr-xcore/java/android/server/BluetoothService.java44
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java4
-rw-r--r--core/java/android/speech/tts/AudioPlaybackHandler.java3
-rwxr-xr-xcore/java/android/speech/tts/TextToSpeech.java20
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java6
-rw-r--r--core/java/android/text/TextLine.java24
-rw-r--r--core/java/android/text/method/Touch.java40
-rw-r--r--core/java/android/util/SparseArray.java1
-rw-r--r--core/java/android/view/GLES20Canvas.java17
-rw-r--r--core/java/android/view/HardwareRenderer.java12
-rw-r--r--core/java/android/view/IWindowSession.aidl13
-rwxr-xr-xcore/java/android/view/KeyEvent.java22
-rw-r--r--core/java/android/view/SurfaceView.java152
-rw-r--r--core/java/android/view/ViewRootImpl.java39
-rw-r--r--core/java/android/view/VolumePanel.java22
-rw-r--r--core/java/android/view/WindowManagerImpl.java27
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java36
-rw-r--r--core/java/android/view/accessibility/AccessibilityInteractionClient.java240
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java55
-rw-r--r--core/java/android/view/accessibility/AccessibilityRecord.java50
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl2
-rw-r--r--core/java/android/webkit/CookieManager.java11
-rw-r--r--core/java/android/webkit/WebView.java66
-rw-r--r--core/java/android/webkit/WebViewCore.java15
-rw-r--r--core/java/android/webkit/ZoomManager.java8
-rw-r--r--core/java/android/widget/NumberPicker.java53
-rw-r--r--core/java/android/widget/TextView.java172
-rw-r--r--core/java/com/android/internal/util/StateMachine.java44
-rw-r--r--core/res/res/anim/app_starting_exit.xml3
-rw-r--r--core/res/res/layout/date_picker.xml3
-rw-r--r--core/res/res/layout/global_actions_item.xml58
-rw-r--r--core/res/res/values-af/strings.xml2
-rw-r--r--core/res/res/values-de/strings.xml4
-rw-r--r--core/res/res/values-es/strings.xml10
-rw-r--r--core/res/res/values-fr/strings.xml4
-rw-r--r--core/res/res/values-pt-rPT/strings.xml20
-rw-r--r--core/res/res/values-ru/strings.xml2
-rw-r--r--core/res/res/values-sw/strings.xml32
-rw-r--r--core/res/res/values-vi/strings.xml4
-rw-r--r--core/res/res/values-zh-rCN/strings.xml10
-rw-r--r--core/res/res/values-zh-rTW/strings.xml4
-rw-r--r--core/res/res/values-zu/strings.xml6
-rwxr-xr-xcore/res/res/values/attrs.xml4
-rwxr-xr-xcore/res/res/values/config.xml3
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java3
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java4
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java11
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java131
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java7
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java12
-rw-r--r--core/tests/bluetoothtests/AndroidManifest.xml2
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java11
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java2
-rw-r--r--core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java198
-rw-r--r--data/keyboards/Generic.kl9
-rwxr-xr-xdocs/html/guide/market/billing/billing_admin.jd275
-rw-r--r--docs/html/guide/practices/ui_guidelines/widget_design.jd12
-rw-r--r--docs/html/guide/topics/appwidgets/index.jd4
-rw-r--r--docs/html/guide/topics/renderscript/index.jd7
-rwxr-xr-xdocs/html/images/billing_list_form_2.pngbin0 -> 140745 bytes
-rwxr-xr-xdocs/html/images/billing_product_list.pngbin55100 -> 67155 bytes
-rw-r--r--docs/html/resources/dashboard/opengl.jd8
-rw-r--r--docs/html/resources/dashboard/platform-versions.jd22
-rw-r--r--docs/html/resources/dashboard/screens.jd12
-rw-r--r--include/gui/SurfaceTexture.h26
-rw-r--r--include/media/IStreamSource.h17
-rw-r--r--include/media/stagefright/ACodec.h2
-rw-r--r--include/ui/GraphicBuffer.h1
-rwxr-xr-xinclude/ui/KeycodeLabels.h4
-rw-r--r--libs/gui/SurfaceTexture.cpp399
-rw-r--r--libs/gui/tests/SurfaceTexture_test.cpp111
-rw-r--r--libs/hwui/FontRenderer.cpp12
-rw-r--r--libs/hwui/OpenGLRenderer.cpp6
-rw-r--r--libs/rs/rsScriptC.cpp20
-rw-r--r--media/libmedia/IStreamSource.cpp2
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp90
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp7
-rw-r--r--media/libmediaplayerservice/nuplayer/StreamingSource.cpp17
-rw-r--r--media/libstagefright/ACodec.cpp32
-rw-r--r--media/libstagefright/AVIExtractor.cpp2
-rw-r--r--media/libstagefright/SurfaceMediaSource.cpp2
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.cpp85
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.h17
-rw-r--r--media/libstagefright/mpeg2ts/AnotherPacketSource.cpp25
-rw-r--r--media/libstagefright/mpeg2ts/AnotherPacketSource.h3
-rw-r--r--media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp2
-rwxr-xr-xmedia/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java14
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java8
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java147
-rw-r--r--native/include/android/keycodes.h4
-rw-r--r--opengl/libs/EGL/eglApi.cpp8
-rw-r--r--opengl/specs/README3
-rw-r--r--packages/SettingsProvider/res/values-vi/strings.xml2
-rw-r--r--packages/SettingsProvider/res/xml/bookmarks.xml25
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java83
-rw-r--r--packages/SystemUI/AndroidManifest.xml20
-rw-r--r--packages/SystemUI/res/layout/global_screenshot.xml15
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/DreamsDockLauncher.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java128
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java1
-rw-r--r--policy/src/com/android/internal/policy/impl/GlobalActions.java4
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java182
-rw-r--r--services/java/com/android/server/DeviceStorageMonitorService.java1
-rw-r--r--services/java/com/android/server/EventLogTags.logtags6
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java9
-rw-r--r--services/java/com/android/server/PowerManagerService.java32
-rw-r--r--services/java/com/android/server/TextServicesManagerService.java10
-rw-r--r--services/java/com/android/server/UiModeManagerService.java2
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java7
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityManagerService.java112
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java115
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java6
-rw-r--r--services/java/com/android/server/am/ActivityStack.java24
-rw-r--r--services/java/com/android/server/wm/Session.java8
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java154
-rw-r--r--services/java/com/android/server/wm/WindowState.java74
-rw-r--r--services/surfaceflinger/Android.mk1
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp10
-rw-r--r--services/surfaceflinger/SurfaceTextureLayer.cpp2
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnection.java19
-rw-r--r--tests/FrameworkPerf/res/layout/main.xml17
-rw-r--r--tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java30
-rw-r--r--tests/FrameworkPerf/src/com/android/frameworkperf/TestArgs.java3
-rw-r--r--tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java17
-rw-r--r--tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java6
159 files changed, 3203 insertions, 1739 deletions
diff --git a/api/current.txt b/api/current.txt
index 23b441b..c62d82b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5502,7 +5502,16 @@ package android.content {
field public static final java.lang.String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
field public static final java.lang.String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
field public static final java.lang.String CATEGORY_ALTERNATIVE = "android.intent.category.ALTERNATIVE";
+ field public static final java.lang.String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER";
+ field public static final java.lang.String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR";
+ field public static final java.lang.String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
+ field public static final java.lang.String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
+ field public static final java.lang.String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
+ field public static final java.lang.String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
+ field public static final java.lang.String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
field public static final java.lang.String CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET";
+ field public static final java.lang.String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING";
+ field public static final java.lang.String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
field public static final java.lang.String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";
field public static final java.lang.String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK";
field public static final java.lang.String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
@@ -14778,6 +14787,7 @@ package android.os {
field public static final int FLAG_ONEWAY = 1; // 0x1
field public static final int INTERFACE_TRANSACTION = 1598968902; // 0x5f4e5446
field public static final int LAST_CALL_TRANSACTION = 16777215; // 0xffffff
+ field public static final int LIKE_TRANSACTION = 1598835019; // 0x5f4c494b
field public static final int PING_TRANSACTION = 1599098439; // 0x5f504e47
field public static final int TWEET_TRANSACTION = 1599362900; // 0x5f545754
}
@@ -17056,7 +17066,7 @@ package android.provider {
field public static final java.lang.String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
field public static final java.lang.String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH = "android.media.action.MEDIA_PLAY_FROM_SEARCH";
field public static final java.lang.String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH";
- field public static final java.lang.String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
+ field public static final deprecated java.lang.String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
field public static final java.lang.String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
field public static final java.lang.String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
field public static final java.lang.String MEDIA_IGNORE_FILENAME = ".nomedia";
@@ -22215,6 +22225,8 @@ package android.view {
field public static final int KEYCODE_BUTTON_Y = 100; // 0x64
field public static final int KEYCODE_BUTTON_Z = 101; // 0x65
field public static final int KEYCODE_C = 31; // 0x1f
+ field public static final int KEYCODE_CALCULATOR = 210; // 0xd2
+ field public static final int KEYCODE_CALENDAR = 208; // 0xd0
field public static final int KEYCODE_CALL = 5; // 0x5
field public static final int KEYCODE_CAMERA = 27; // 0x1b
field public static final int KEYCODE_CAPS_LOCK = 115; // 0x73
@@ -22223,6 +22235,7 @@ package android.view {
field public static final int KEYCODE_CHANNEL_UP = 166; // 0xa6
field public static final int KEYCODE_CLEAR = 28; // 0x1c
field public static final int KEYCODE_COMMA = 55; // 0x37
+ field public static final int KEYCODE_CONTACTS = 207; // 0xcf
field public static final int KEYCODE_CTRL_LEFT = 113; // 0x71
field public static final int KEYCODE_CTRL_RIGHT = 114; // 0x72
field public static final int KEYCODE_D = 32; // 0x20
@@ -22290,6 +22303,7 @@ package android.view {
field public static final int KEYCODE_MINUS = 69; // 0x45
field public static final int KEYCODE_MOVE_END = 123; // 0x7b
field public static final int KEYCODE_MOVE_HOME = 122; // 0x7a
+ field public static final int KEYCODE_MUSIC = 209; // 0xd1
field public static final int KEYCODE_MUTE = 91; // 0x5b
field public static final int KEYCODE_N = 42; // 0x2a
field public static final int KEYCODE_NOTIFICATION = 83; // 0x53
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 26b9113..4ede33f 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -184,6 +184,7 @@ int free_cache(int64_t free_size)
DIR *d;
struct dirent *de;
int64_t avail;
+ char datadir[PKG_PATH_MAX];
avail = disk_free();
if (avail < 0) return -1;
@@ -191,9 +192,14 @@ int free_cache(int64_t free_size)
LOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
if (avail >= free_size) return 0;
- d = opendir(android_data_dir.path);
+ if (create_persona_path(datadir, 0)) {
+ LOGE("couldn't get directory for persona 0");
+ return -1;
+ }
+
+ d = opendir(datadir);
if (d == NULL) {
- LOGE("cannot open %s: %s\n", android_data_dir.path, strerror(errno));
+ LOGE("cannot open %s: %s\n", datadir, strerror(errno));
return -1;
}
dfd = dirfd(d);
@@ -578,19 +584,6 @@ fail:
return -1;
}
-int create_move_path(char path[PKG_PATH_MAX],
- const char* pkgname,
- const char* leaf,
- uid_t persona)
-{
- if ((android_data_dir.len + strlen(pkgname) + strlen(leaf) + 1) >= PKG_PATH_MAX) {
- return -1;
- }
-
- sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
- return 0;
-}
-
void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
struct stat* statbuf)
{
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index c5872b8..173cabf 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -105,6 +105,11 @@ int create_pkg_path(char path[PKG_PATH_MAX],
int create_persona_path(char path[PKG_PATH_MAX],
uid_t persona);
+int create_move_path(char path[PKG_PATH_MAX],
+ const char* pkgname,
+ const char* leaf,
+ uid_t persona);
+
int is_valid_package_name(const char* pkgname);
int create_cache_path(char path[PKG_PATH_MAX], const char *src);
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 1128fce..7cb9b37 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -34,6 +34,16 @@ extern "C" {
#define TEST_SYSTEM_DIR1 "/system/app/"
#define TEST_SYSTEM_DIR2 "/vendor/app/"
+#define REALLY_LONG_APP_NAME "com.example." \
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+#define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
+ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
+ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
+ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_"
+
namespace android {
class UtilsTest : public testing::Test {
@@ -210,7 +220,7 @@ TEST_F(UtilsTest, CheckSystemApp_BadPathEscapeFail) {
TEST_F(UtilsTest, GetPathFromString_NullPathFail) {
dir_rec_t test1;
- EXPECT_EQ(-1, get_path_from_string(&test1, NULL))
+ EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL))
<< "Should not allow NULL as a path.";
}
@@ -327,6 +337,50 @@ TEST_F(UtilsTest, CreatePkgPathInDir_ProtectedDir) {
<< "Package path should be in /data/app-private/";
}
+TEST_F(UtilsTest, CreatePersonaPath_Primary) {
+ char path[PKG_PATH_MAX];
+
+ EXPECT_EQ(0, create_persona_path(path, 0))
+ << "Should successfully build primary user path.";
+
+ EXPECT_STREQ("/data/data/", path)
+ << "Primary user should have correct path";
+}
+
+TEST_F(UtilsTest, CreatePersonaPath_Secondary) {
+ char path[PKG_PATH_MAX];
+
+ EXPECT_EQ(0, create_persona_path(path, 1))
+ << "Should successfully build primary user path.";
+
+ EXPECT_STREQ("/data/user/1/", path)
+ << "Primary user should have correct path";
+}
+
+TEST_F(UtilsTest, CreateMovePath_Primary) {
+ char path[PKG_PATH_MAX];
+
+ EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0))
+ << "Should be able to create move path for primary user";
+
+ EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path)
+ << "Primary user package directory should be created correctly";
+}
+
+TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) {
+ char path[PKG_PATH_MAX];
+
+ EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0))
+ << "Should fail to create move path for primary user";
+}
+
+TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) {
+ char path[PKG_PATH_MAX];
+
+ EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0))
+ << "Should fail to create move path for primary user";
+}
+
TEST_F(UtilsTest, CopyAndAppend_Normal) {
//int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix)
dir_rec_t dst;
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index 3099b83..a53a93c 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -109,7 +109,7 @@ int create_persona_path(char path[PKG_PATH_MAX],
uid_len = 0;
} else {
persona_prefix = SECONDARY_USER_PREFIX;
- uid_len = snprintf(NULL, 0, "%d", persona);
+ uid_len = snprintf(NULL, 0, "%d/", persona);
}
char *dst = path;
@@ -126,7 +126,7 @@ int create_persona_path(char path[PKG_PATH_MAX],
LOGE("Error building user path");
return -1;
}
- int ret = snprintf(dst, dst_size, "%d", persona);
+ int ret = snprintf(dst, dst_size, "%d/", persona);
if (ret < 0 || (size_t) ret != uid_len) {
LOGE("Error appending persona id to path");
return -1;
@@ -135,6 +135,20 @@ int create_persona_path(char path[PKG_PATH_MAX],
return 0;
}
+int create_move_path(char path[PKG_PATH_MAX],
+ const char* pkgname,
+ const char* leaf,
+ uid_t persona)
+{
+ if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
+ >= PKG_PATH_MAX) {
+ return -1;
+ }
+
+ sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
+ return 0;
+}
+
/**
* Checks whether the package name is valid. Returns -1 on error and
* 0 on success.
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 64a2755..211be52 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -16,8 +16,6 @@
package android.accessibilityservice;
-import com.android.internal.os.HandlerCaller;
-
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
@@ -25,8 +23,11 @@ import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.os.HandlerCaller;
+
/**
* An accessibility service runs in the background and receives callbacks by the system
* when {@link AccessibilityEvent}s are fired. Such events denote some state transition
@@ -219,7 +220,7 @@ public abstract class AccessibilityService extends Service {
private AccessibilityServiceInfo mInfo;
- IAccessibilityServiceConnection mConnection;
+ private int mConnectionId;
/**
* Callback for {@link android.view.accessibility.AccessibilityEvent}s.
@@ -264,9 +265,11 @@ public abstract class AccessibilityService extends Service {
* AccessibilityManagerService.
*/
private void sendServiceInfo() {
- if (mInfo != null && mConnection != null) {
+ IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+ if (mInfo != null && connection != null) {
try {
- mConnection.setServiceInfo(mInfo);
+ connection.setServiceInfo(mInfo);
} catch (RemoteException re) {
Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
}
@@ -302,8 +305,9 @@ public abstract class AccessibilityService extends Service {
mCaller = new HandlerCaller(context, this);
}
- public void setConnection(IAccessibilityServiceConnection connection) {
- Message message = mCaller.obtainMessageO(DO_SET_SET_CONNECTION, connection);
+ public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
+ Message message = mCaller.obtainMessageIO(DO_SET_SET_CONNECTION, connectionId,
+ connection);
mCaller.sendMessage(message);
}
@@ -330,8 +334,19 @@ public abstract class AccessibilityService extends Service {
mTarget.onInterrupt();
return;
case DO_SET_SET_CONNECTION :
- mConnection = ((IAccessibilityServiceConnection) message.obj);
- mTarget.onServiceConnected();
+ final int connectionId = message.arg1;
+ IAccessibilityServiceConnection connection =
+ (IAccessibilityServiceConnection) message.obj;
+ if (connection != null) {
+ AccessibilityInteractionClient.getInstance().addConnection(connectionId,
+ connection);
+ mConnectionId = connectionId;
+ mTarget.onServiceConnected();
+ } else {
+ AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
+ mConnectionId = AccessibilityInteractionClient.NO_ID;
+ // TODO: Do we need a onServiceDisconnected callback?
+ }
return;
default :
Log.w(LOG_TAG, "Unknown message type " + message.what);
diff --git a/core/java/android/accessibilityservice/IEventListener.aidl b/core/java/android/accessibilityservice/IEventListener.aidl
index 5b849f1..5536b3c 100644
--- a/core/java/android/accessibilityservice/IEventListener.aidl
+++ b/core/java/android/accessibilityservice/IEventListener.aidl
@@ -26,7 +26,7 @@ import android.view.accessibility.AccessibilityEvent;
*/
oneway interface IEventListener {
- void setConnection(in IAccessibilityServiceConnection connection);
+ void setConnection(in IAccessibilityServiceConnection connection, int connectionId);
void onAccessibilityEvent(in AccessibilityEvent event);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 303f81b..0c761fc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -175,11 +175,11 @@ public final class ActivityThread {
// These can be accessed by multiple threads; mPackages is the lock.
// XXX For now we keep around information about all packages we have
// seen, not removing entries from this map.
- // NOTE: The activity manager in its process needs to call in to
+ // NOTE: The activity and window managers need to call in to
// ActivityThread to do things like update resource configurations,
- // which means this lock gets held while the activity manager holds its
- // own lock. Thus you MUST NEVER call back into the activity manager
- // or anything that depends on it while holding this lock.
+ // which means this lock gets held while the activity and window managers
+ // holds their own lock. Thus you MUST NEVER call back into the activity manager
+ // or window manager or anything that depends on them while holding this lock.
final HashMap<String, WeakReference<LoadedApk>> mPackages
= new HashMap<String, WeakReference<LoadedApk>>();
final HashMap<String, WeakReference<LoadedApk>> mResourcePackages
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 8ed7481..180a442 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -625,7 +625,7 @@ final class ApplicationPackageManager extends PackageManager {
return info.activityInfo.loadIcon(this);
}
- throw new NameNotFoundException(intent.toURI());
+ throw new NameNotFoundException(intent.toUri(0));
}
@Override public Drawable getDefaultActivityIcon() {
@@ -728,15 +728,22 @@ final class ApplicationPackageManager extends PackageManager {
private Drawable getCachedIcon(ResourceName name) {
synchronized (sSync) {
- WeakReference<Drawable> wr = sIconCache.get(name);
+ WeakReference<Drawable.ConstantState> wr = sIconCache.get(name);
if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
+ name + ": " + wr);
if (wr != null) { // we have the activity
- Drawable dr = wr.get();
- if (dr != null) {
- if (DEBUG_ICONS) Log.v(TAG, "Get cached drawable for "
- + name + ": " + dr);
- return dr;
+ Drawable.ConstantState state = wr.get();
+ if (state != null) {
+ if (DEBUG_ICONS) {
+ Log.v(TAG, "Get cached drawable state for " + name + ": " + state);
+ }
+ // Note: It's okay here to not use the newDrawable(Resources) variant
+ // of the API. The ConstantState comes from a drawable that was
+ // originally created by passing the proper app Resources instance
+ // which means the state should already contain the proper
+ // resources specific information (like density.) See
+ // BitmapDrawable.BitmapState for instance.
+ return state.newDrawable();
}
// our entry has been purged
sIconCache.remove(name);
@@ -747,14 +754,12 @@ final class ApplicationPackageManager extends PackageManager {
private void putCachedIcon(ResourceName name, Drawable dr) {
synchronized (sSync) {
- sIconCache.put(name, new WeakReference<Drawable>(dr));
- if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
- + name + ": " + dr);
+ sIconCache.put(name, new WeakReference<Drawable.ConstantState>(dr.getConstantState()));
+ if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable state for " + name + ": " + dr);
}
}
- static final void handlePackageBroadcast(int cmd, String[] pkgList,
- boolean hasPkgInfo) {
+ static void handlePackageBroadcast(int cmd, String[] pkgList, boolean hasPkgInfo) {
boolean immediateGc = false;
if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
immediateGc = true;
@@ -1226,8 +1231,8 @@ final class ApplicationPackageManager extends PackageManager {
private final IPackageManager mPM;
private static final Object sSync = new Object();
- private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
- = new HashMap<ResourceName, WeakReference<Drawable> >();
- private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
- = new HashMap<ResourceName, WeakReference<CharSequence> >();
+ private static HashMap<ResourceName, WeakReference<Drawable.ConstantState>> sIconCache
+ = new HashMap<ResourceName, WeakReference<Drawable.ConstantState>>();
+ private static HashMap<ResourceName, WeakReference<CharSequence>> sStringCache
+ = new HashMap<ResourceName, WeakReference<CharSequence>>();
}
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 8b70370..bf8fde0 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -91,13 +91,14 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
mCallBack = callBack;
- setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this);
- setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel), (OnClickListener) null);
+ Context themeContext = getContext();
+ setButton(BUTTON_POSITIVE, themeContext.getText(R.string.date_time_set), this);
+ setButton(BUTTON_NEGATIVE, themeContext.getText(R.string.cancel), (OnClickListener) null);
setIcon(0);
setTitle(R.string.date_picker_dialog_title);
LayoutInflater inflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ (LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.date_picker_dialog, null);
setView(view);
mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index a990ee9..353b415 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -92,16 +92,16 @@ public class TimePickerDialog extends AlertDialog
mInitialMinute = minute;
mIs24HourView = is24HourView;
- setCanceledOnTouchOutside(false);
setIcon(0);
setTitle(R.string.time_picker_dialog_title);
- setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this);
- setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel),
+ Context themeContext = getContext();
+ setButton(BUTTON_POSITIVE, themeContext.getText(R.string.date_time_set), this);
+ setButton(BUTTON_NEGATIVE, themeContext.getText(R.string.cancel),
(OnClickListener) null);
LayoutInflater inflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ (LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.time_picker_dialog, null);
setView(view);
mTimePicker = (TimePicker) view.findViewById(R.id.timePicker);
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 96f3290..7300107 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -129,6 +129,10 @@ public final class BluetoothA2dp implements BluetoothProfile {
}
}
+ /*package*/ void close() {
+ mServiceListener = null;
+ }
+
/**
* Initiate connection to a profile of the remote bluetooth device.
*
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d971652..5f5ba50 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1180,11 +1180,29 @@ public final class BluetoothAdapter {
* @param proxy Profile proxy object
*/
public void closeProfileProxy(int profile, BluetoothProfile proxy) {
- if (profile == BluetoothProfile.HEADSET) {
- BluetoothHeadset headset = (BluetoothHeadset)proxy;
- if (headset != null) {
+ if (proxy == null) return;
+
+ switch (profile) {
+ case BluetoothProfile.HEADSET:
+ BluetoothHeadset headset = (BluetoothHeadset)proxy;
headset.close();
- }
+ break;
+ case BluetoothProfile.A2DP:
+ BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
+ a2dp.close();
+ break;
+ case BluetoothProfile.INPUT_DEVICE:
+ BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
+ iDev.close();
+ break;
+ case BluetoothProfile.PAN:
+ BluetoothPan pan = (BluetoothPan)proxy;
+ pan.close();
+ break;
+ case BluetoothProfile.HEALTH:
+ BluetoothHealth health = (BluetoothHealth)proxy;
+ health.close();
+ break;
}
}
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index b1d0070..c9603bf 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -109,6 +109,8 @@ public final class BluetoothDeviceProfileState extends StateMachine {
private BluetoothA2dpService mA2dpService;
private BluetoothHeadset mHeadsetService;
private BluetoothPbap mPbapService;
+ private PbapServiceListener mPbap;
+ private BluetoothAdapter mAdapter;
private boolean mPbapServiceConnected;
private boolean mAutoConnectionPending;
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
@@ -249,11 +251,11 @@ public final class BluetoothDeviceProfileState extends StateMachine {
mContext.registerReceiver(mBroadcastReceiver, filter);
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mAdapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
BluetoothProfile.HEADSET);
// TODO(): Convert PBAP to the new Profile APIs.
- PbapServiceListener p = new PbapServiceListener();
+ mPbap = new PbapServiceListener();
mIncomingConnections = mService.getIncomingState(address);
mIncomingRejectTimer = readTimerValue();
@@ -414,6 +416,26 @@ public final class BluetoothDeviceProfileState extends StateMachine {
case TRANSITION_TO_STABLE:
// ignore.
break;
+ case SM_QUIT_CMD:
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ mBroadcastReceiver = null;
+ mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadsetService);
+ mBluetoothProfileServiceListener = null;
+ mOutgoingHandsfree = null;
+ mPbap = null;
+ mPbapService.close();
+ mPbapService = null;
+ mIncomingHid = null;
+ mOutgoingHid = null;
+ mIncomingHandsfree = null;
+ mOutgoingHandsfree = null;
+ mIncomingA2dp = null;
+ mOutgoingA2dp = null;
+ mBondedDevice = null;
+ // There is a problem in the State Machine code
+ // where things are not cleaned up properly, when quit message
+ // is handled so return NOT_HANDLED as a workaround.
+ return NOT_HANDLED;
default:
return NOT_HANDLED;
}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 8f2b3d8..2bbf008 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -245,6 +245,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
mContext.unbindService(mConnection);
mConnection = null;
}
+ mServiceListener = null;
}
/**
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 9b2b8ca..f850c02 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -452,6 +452,10 @@ public final class BluetoothHealth implements BluetoothProfile {
}
}
+ /*package*/ void close() {
+ mServiceListener = null;
+ }
+
private boolean isEnabled() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index 282b70a..1a9e011 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -118,6 +118,10 @@ public final class BluetoothInputDevice implements BluetoothProfile {
}
}
+ /*package*/ void close() {
+ mServiceListener = null;
+ }
+
/**
* Initiate connection to a profile of the remote bluetooth device.
*
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 7490f9e..5d9d8be 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -139,6 +139,10 @@ public final class BluetoothPan implements BluetoothProfile {
}
}
+ /*package*/ void close() {
+ mServiceListener = null;
+ }
+
/**
* Initiate connection to a profile of the remote bluetooth device.
*
@@ -299,4 +303,4 @@ public final class BluetoothPan implements BluetoothProfile {
private static void log(String msg) {
Log.d(TAG, msg);
}
-} \ No newline at end of file
+}
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index 4be077c..2683bef 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -69,7 +69,7 @@ public class BluetoothPbap {
private IBluetoothPbap mService;
private final Context mContext;
- private final ServiceListener mServiceListener;
+ private ServiceListener mServiceListener;
/** There was an error trying to obtain the state */
public static final int STATE_ERROR = -1;
@@ -138,6 +138,7 @@ public class BluetoothPbap {
mContext.unbindService(mConnection);
mConnection = null;
}
+ mServiceListener = null;
}
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 45a42e4..9948985 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2310,6 +2310,74 @@ public class Intent implements Parcelable, Cloneable {
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
+ // Application launch intent categories (see addCategory()).
+
+ /**
+ * Used with {@link #ACTION_MAIN} to launch the browser application.
+ * The activity should be able to browse the Internet.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER";
+
+ /**
+ * Used with {@link #ACTION_MAIN} to launch the calculator application.
+ * The activity should be able to perform standard arithmetic operations.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR";
+
+ /**
+ * Used with {@link #ACTION_MAIN} to launch the calendar application.
+ * The activity should be able to view and manipulate calendar entries.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
+
+ /**
+ * Used with {@link #ACTION_MAIN} to launch the contacts application.
+ * The activity should be able to view and manipulate address book entries.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
+
+ /**
+ * Used with {@link #ACTION_MAIN} to launch the email application.
+ * The activity should be able to send and receive email.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
+
+ /**
+ * Used with {@link #ACTION_MAIN} to launch the gallery application.
+ * The activity should be able to view and manipulate image and video files
+ * stored on the device.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
+
+ /**
+ * Used with {@link #ACTION_MAIN} to launch the maps application.
+ * The activity should be able to show the user's current location and surroundings.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
+
+ /**
+ * Used with {@link #ACTION_MAIN} to launch the messaging application.
+ * The activity should be able to send and receive text messages.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING";
+
+ /**
+ * Used with {@link #ACTION_MAIN} to launch the music application.
+ * The activity should be able to play, browse, or manipulate music files stored on the device.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
+
+ // ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
// Standard extra data keys.
/**
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 4fc63ed..72431f3 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -156,4 +156,27 @@ public class ExtractEditText extends EditText {
mIME.onViewClicked(false);
}
}
+
+ /**
+ * Delete the range of text, supposedly valid
+ * @hide
+ */
+ @Override
+ protected void deleteText_internal(int start, int end) {
+ // Do not call the super method. This will change the source TextView instead, which
+ // will update the ExtractTextView.
+ mIME.onExtractedDeleteText(start, end);
+ }
+
+ /**
+ * Replaces the range of text [start, end[ by replacement text
+ * @hide
+ */
+ @Override
+ protected void replaceText_internal(int start, int end, CharSequence text) {
+ // Do not call the super method. This will change the source TextView instead, which
+ // will update the ExtractTextView.
+ mIME.onExtractedReplaceText(start, end, text);
+ }
+
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 60188ea..02839db 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1982,7 +1982,29 @@ public class InputMethodService extends AbstractInputMethodService {
conn.setSelection(start, end);
}
}
-
+
+ /**
+ * @hide
+ */
+ public void onExtractedDeleteText(int start, int end) {
+ InputConnection conn = getCurrentInputConnection();
+ if (conn != null) {
+ conn.setSelection(start, start);
+ conn.deleteSurroundingText(0, end-start);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void onExtractedReplaceText(int start, int end, CharSequence text) {
+ InputConnection conn = getCurrentInputConnection();
+ if (conn != null) {
+ conn.setComposingRegion(start, end);
+ conn.commitText(text, 1);
+ }
+ }
+
/**
* This is called when the user has clicked on the extracted text view,
* when running in fullscreen mode. The default implementation hides
@@ -1998,7 +2020,7 @@ public class InputMethodService extends AbstractInputMethodService {
setCandidatesViewShown(false);
}
}
-
+
/**
* This is called when the user has performed a cursor movement in the
* extracted text view, when it is running in fullscreen mode. The default
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 81defd6..0586d9e 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -128,6 +128,19 @@ public interface IBinder {
int TWEET_TRANSACTION = ('_'<<24)|('T'<<16)|('W'<<8)|'T';
/**
+ * IBinder protocol transaction code: tell an app asynchronously that the
+ * caller likes it. The app is responsible for incrementing and maintaining
+ * its own like counter, and may display this value to the user to indicate the
+ * quality of the app. This is an optional command that applications do not
+ * need to handle, so the default implementation is to do nothing.
+ *
+ * <p>There is no response returned and nothing about the
+ * system will be functionally affected by it, but it will improve the
+ * app's self-esteem.
+ */
+ int LIKE_TRANSACTION = ('_'<<24)|('L'<<16)|('I'<<8)|'K';
+
+ /**
* Flag to {@link #transact}: this is a one-way call, meaning that the
* caller returns immediately, without waiting for a result from the
* callee. Applies only if the caller and callee are in different
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 5f111eb..4e01672 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -40,8 +40,6 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.text.Collator;
/**
* The Media provider contains meta data for all available media on both internal
@@ -66,7 +64,10 @@ public final class MediaStore {
/**
* Activity Action: Launch a music player.
* The activity should be able to play, browse, or manipulate music files stored on the device.
+ *
+ * @deprecated Use {@link android.content.Intent#CATEGORY_APP_MUSIC} instead.
*/
+ @Deprecated
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ee3215c..15e4438 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4019,28 +4019,6 @@ public final class Settings {
public static final String SETUP_PREPAID_DETECTION_REDIR_HOST =
"setup_prepaid_detection_redir_host";
- /**
- * Whether the screensaver is enabled.
- * @hide
- */
- public static final String SCREENSAVER_ENABLED = "screensaver_enabled";
-
- /**
- * The user's chosen screensaver component.
- *
- * This component will be launched by the PhoneWindowManager after a timeout when not on
- * battery, or upon dock insertion (if SCREENSAVER_ACTIVATE_ON_DOCK is set to 1).
- * @hide
- */
- public static final String SCREENSAVER_COMPONENT = "screensaver_component";
-
- /**
- * Whether the screensaver should be automatically launched when the device is inserted
- * into a (desk) dock.
- * @hide
- */
- public static final String SCREENSAVER_ACTIVATE_ON_DOCK = "screensaver_activate_on_dock";
-
/** {@hide} */
public static final String NETSTATS_ENABLED = "netstats_enabled";
/** {@hide} */
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 28e231e..94fbbc8 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -145,7 +145,12 @@ public class BluetoothService extends IBluetooth.Stub {
private final ArrayList<String> mUuidIntentTracker;
private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
- private final HashMap<Integer, Pair<Integer, IBinder>> mServiceRecordToPid;
+ private static class ServiceRecordClient {
+ int pid;
+ IBinder binder;
+ IBinder.DeathRecipient death;
+ }
+ private final HashMap<Integer, ServiceRecordClient> mServiceRecordToPid;
private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState;
private final BluetoothProfileState mA2dpProfileState;
@@ -221,7 +226,7 @@ public class BluetoothService extends IBluetooth.Stub {
mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
mUuidIntentTracker = new ArrayList<String>();
mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
- mServiceRecordToPid = new HashMap<Integer, Pair<Integer, IBinder>>();
+ mServiceRecordToPid = new HashMap<Integer, ServiceRecordClient>();
mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>();
mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);
mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP);
@@ -1528,11 +1533,17 @@ public class BluetoothService extends IBluetooth.Stub {
return -1;
}
- int pid = Binder.getCallingPid();
- mServiceRecordToPid.put(new Integer(handle), new Pair<Integer, IBinder>(pid, b));
+ ServiceRecordClient client = new ServiceRecordClient();
+ client.pid = Binder.getCallingPid();
+ client.binder = b;
+ client.death = new Reaper(handle, client.pid, RFCOMM_RECORD_REAPER);
+ mServiceRecordToPid.put(new Integer(handle), client);
try {
- b.linkToDeath(new Reaper(handle, pid, RFCOMM_RECORD_REAPER), 0);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
+ b.linkToDeath(client.death, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ client.death = null;
+ }
return handle;
}
@@ -1547,10 +1558,15 @@ public class BluetoothService extends IBluetooth.Stub {
}
private synchronized void checkAndRemoveRecord(int handle, int pid) {
- Pair<Integer, IBinder> pidPair = mServiceRecordToPid.get(handle);
- if (pidPair != null && pid == pidPair.first) {
+ ServiceRecordClient client = mServiceRecordToPid.get(handle);
+ if (client != null && pid == client.pid) {
if (DBG) Log.d(TAG, "Removing service record " +
Integer.toHexString(handle) + " for pid " + pid);
+
+ if (client.death != null) {
+ client.binder.unlinkToDeath(client.death, 0);
+ }
+
mServiceRecordToPid.remove(handle);
removeServiceRecordNative(handle);
}
@@ -1880,7 +1896,7 @@ public class BluetoothService extends IBluetooth.Stub {
private void dumpApplicationServiceRecords(PrintWriter pw) {
pw.println("\n--Application Service Records--");
for (Integer handle : mServiceRecordToPid.keySet()) {
- Integer pid = mServiceRecordToPid.get(handle).first;
+ Integer pid = mServiceRecordToPid.get(handle).pid;
pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
}
}
@@ -2374,16 +2390,18 @@ public class BluetoothService extends IBluetooth.Stub {
}
BluetoothDeviceProfileState addProfileState(String address, boolean setTrust) {
- BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
- if (state != null) return state;
-
- state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust);
+ BluetoothDeviceProfileState state =
+ new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust);
mDeviceProfileState.put(address, state);
state.start();
return state;
}
void removeProfileState(String address) {
+ BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
+ if (state == null) return;
+
+ state.quit();
mDeviceProfileState.remove(address);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a9a628a..18167b6 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -608,7 +608,7 @@ public abstract class WallpaperService extends Service {
final int relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
- View.VISIBLE, false, mWinFrame, mContentInsets,
+ View.VISIBLE, 0, mWinFrame, mContentInsets,
mVisibleInsets, mConfiguration, mSurfaceHolder.mSurface);
if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
@@ -654,7 +654,7 @@ public abstract class WallpaperService extends Service {
}
redrawNeeded |= creating
- || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0;
+ || (relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0;
if (forceReport || creating || surfaceCreating
|| formatChanged || sizeChanged) {
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index fd00dce..46a78dc 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -428,7 +428,8 @@ class AudioPlaybackHandler {
final AudioTrack audioTrack = params.getAudioTrack();
if (audioTrack == null) {
- params.getDispatcher().dispatchOnError();
+ // There was already a call to handleSynthesisDone for
+ // this token.
return;
}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 38699ea..a220615 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -490,6 +490,7 @@ public class TextToSpeech {
private final Map<String, Uri> mUtterances;
private final Bundle mParams = new Bundle();
private final TtsEngines mEnginesHelper;
+ private final String mPackageName;
private volatile String mCurrentEngine = null;
/**
@@ -518,19 +519,36 @@ public class TextToSpeech {
* @param engine Package name of the TTS engine to use.
*/
public TextToSpeech(Context context, OnInitListener listener, String engine) {
+ this(context, listener, engine, null);
+ }
+
+ /**
+ * Used by the framework to instantiate TextToSpeech objects with a supplied
+ * package name, instead of using {@link android.content.Context#getPackageName()}
+ *
+ * @hide
+ */
+ public TextToSpeech(Context context, OnInitListener listener, String engine,
+ String packageName) {
mContext = context;
mInitListener = listener;
mRequestedEngine = engine;
mEarcons = new HashMap<String, Uri>();
mUtterances = new HashMap<String, Uri>();
+ mUtteranceProgressListener = null;
mEnginesHelper = new TtsEngines(mContext);
+ if (packageName != null) {
+ mPackageName = packageName;
+ } else {
+ mPackageName = mContext.getPackageName();
+ }
initTts();
}
private String getPackageName() {
- return mContext.getPackageName();
+ return mPackageName;
}
private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method) {
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index f82a659..aee678a 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -450,7 +450,7 @@ public abstract class TextToSpeechService extends Service {
@Override
public void dispatchOnDone() {
final String utteranceId = getUtteranceId();
- if (!TextUtils.isEmpty(utteranceId)) {
+ if (utteranceId != null) {
mCallbacks.dispatchOnDone(getCallingApp(), utteranceId);
}
}
@@ -458,7 +458,7 @@ public abstract class TextToSpeechService extends Service {
@Override
public void dispatchOnStart() {
final String utteranceId = getUtteranceId();
- if (!TextUtils.isEmpty(utteranceId)) {
+ if (utteranceId != null) {
mCallbacks.dispatchOnStart(getCallingApp(), utteranceId);
}
}
@@ -466,7 +466,7 @@ public abstract class TextToSpeechService extends Service {
@Override
public void dispatchOnError() {
final String utteranceId = getUtteranceId();
- if (!TextUtils.isEmpty(utteranceId)) {
+ if (utteranceId != null) {
mCallbacks.dispatchOnError(getCallingApp(), utteranceId);
}
}
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 68fea19..b73d900 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -119,6 +119,7 @@ class TextLine {
* @param hasTabs true if the line might contain tabs or emoji
* @param tabStops the tabStops. Can be null.
*/
+ @SuppressWarnings("null")
void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
Directions directions, boolean hasTabs, TabStops tabStops) {
mPaint = paint;
@@ -134,11 +135,12 @@ class TextLine {
mSpanned = null;
boolean hasReplacement = false;
+ SpanSet<ReplacementSpan> replacementSpans = null;
if (text instanceof Spanned) {
mSpanned = (Spanned) text;
- ReplacementSpan[] spans = mSpanned.getSpans(start, limit, ReplacementSpan.class);
- spans = TextUtils.removeEmptySpans(spans, mSpanned, ReplacementSpan.class);
- hasReplacement = spans.length > 0;
+ replacementSpans = new SpanSet<ReplacementSpan>(mSpanned, start, limit,
+ ReplacementSpan.class);
+ hasReplacement = replacementSpans.numberOfSpans > 0;
}
mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT;
@@ -156,10 +158,9 @@ class TextLine {
// zero-width characters.
char[] chars = mChars;
for (int i = start, inext; i < limit; i = inext) {
- inext = mSpanned.nextSpanTransition(i, limit, ReplacementSpan.class);
- ReplacementSpan[] spans = mSpanned.getSpans(i, inext, ReplacementSpan.class);
- spans = TextUtils.removeEmptySpans(spans, mSpanned, ReplacementSpan.class);
- if (spans.length > 0) {
+ // replacementSpans cannot be null if hasReplacement is true
+ inext = replacementSpans.getNextTransition(i, limit);
+ if (replacementSpans.hasSpansIntersecting(i, inext)) {
// transition into a span
chars[i - start] = '\ufffc';
for (int j = i - start + 1, e = inext - start; j < e; ++j) {
@@ -908,6 +909,15 @@ class TextLine {
numberOfSpans = count;
}
+ public boolean hasSpansIntersecting(int start, int end) {
+ for (int i = 0; i < numberOfSpans; i++) {
+ // equal test is valid since both intervals are not empty by construction
+ if (spanStarts[i] >= end || spanEnds[i] <= start) continue;
+ return true;
+ }
+ return false;
+ }
+
int getNextTransition(int start, int limit) {
for (int i = 0; i < numberOfSpans; i++) {
final int spanStart = spanStarts[i];
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index 106a801..3dfd44d 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -35,22 +35,30 @@ public class Touch {
* Y position.
*/
public static void scrollTo(TextView widget, Layout layout, int x, int y) {
- final int verticalPadding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
- final int top = layout.getLineForVertical(y);
- final int bottom = layout.getLineForVertical(y + widget.getHeight() - verticalPadding);
+ final int horizontalPadding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight();
+ final int availableWidth = widget.getWidth() - horizontalPadding;
- int left = Integer.MAX_VALUE;
- int right = 0;
+ final int top = layout.getLineForVertical(y);
Alignment a = layout.getParagraphAlignment(top);
boolean ltr = layout.getParagraphDirection(top) > 0;
- for (int i = top; i <= bottom; i++) {
- left = (int) Math.min(left, layout.getLineLeft(i));
- right = (int) Math.max(right, layout.getLineRight(i));
+ int left, right;
+ if (widget.getHorizontallyScrolling()) {
+ final int verticalPadding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
+ final int bottom = layout.getLineForVertical(y + widget.getHeight() - verticalPadding);
+
+ left = Integer.MAX_VALUE;
+ right = 0;
+
+ for (int i = top; i <= bottom; i++) {
+ left = (int) Math.min(left, layout.getLineLeft(i));
+ right = (int) Math.max(right, layout.getLineRight(i));
+ }
+ } else {
+ left = 0;
+ right = availableWidth;
}
- final int hoizontalPadding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight();
- final int availableWidth = widget.getWidth() - hoizontalPadding;
final int actualWidth = right - left;
if (actualWidth < availableWidth) {
@@ -166,16 +174,24 @@ public class Touch {
return false;
}
+ /**
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ */
public static int getInitialScrollX(TextView widget, Spannable buffer) {
DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class);
return ds.length > 0 ? ds[0].mScrollX : -1;
}
-
+
+ /**
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ */
public static int getInitialScrollY(TextView widget, Spannable buffer) {
DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class);
return ds.length > 0 ? ds[0].mScrollY : -1;
}
-
+
private static class DragState implements NoCopySpan {
public float mX;
public float mY;
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 7cf4579..366abd3 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -134,6 +134,7 @@ public class SparseArray<E> implements Cloneable {
if (i != o) {
keys[o] = keys[i];
values[o] = val;
+ values[i] = null;
}
o++;
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index d948ec2..4ca299f 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -737,8 +737,21 @@ class GLES20Canvas extends HardwareCanvas {
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, src.left, src.top, src.right,
- src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+
+ float left, top, right, bottom;
+ if (src == null) {
+ left = top = 0;
+ right = bitmap.getWidth();
+ bottom = bitmap.getHeight();
+ } else {
+ left = src.left;
+ right = src.right;
+ top = src.top;
+ bottom = src.bottom;
+ }
+
+ nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint);
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f77cf7e..ccb6489 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -219,6 +219,13 @@ public abstract class HardwareRenderer {
abstract int getHeight();
/**
+ * Gets the current canvas associated with this HardwareRenderer.
+ *
+ * @return the current HardwareCanvas
+ */
+ abstract HardwareCanvas getCanvas();
+
+ /**
* Sets the directory to use as a persistent storage for hardware rendering
* resources.
*
@@ -783,6 +790,11 @@ public abstract class HardwareRenderer {
return mHeight;
}
+ @Override
+ HardwareCanvas getCanvas() {
+ return mCanvas;
+ }
+
boolean canDraw() {
return mGl != null && mCanvas != null;
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 282d7be..53d6e1f 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -54,9 +54,8 @@ interface IWindowSession {
* @param requestedWidth The width the window wants to be.
* @param requestedHeight The height the window wants to be.
* @param viewVisibility Window root view's visibility.
- * @param insetsPending Set to true if the client will be later giving
- * internal insets; as a result, the window will not impact other window
- * layouts until the insets are given.
+ * @param flags Request flags: {@link WindowManagerImpl#RELAYOUT_INSETS_PENDING},
+ * {@link WindowManagerImpl#RELAYOUT_DEFER_SURFACE_DESTROY}.
* @param outFrame Rect in which is placed the new position/size on
* screen.
* @param outContentInsets Rect in which is placed the offsets from
@@ -80,11 +79,17 @@ interface IWindowSession {
*/
int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility,
- boolean insetsPending, out Rect outFrame, out Rect outContentInsets,
+ int flags, out Rect outFrame, out Rect outContentInsets,
out Rect outVisibleInsets, out Configuration outConfig,
out Surface outSurface);
/**
+ * If a call to relayout() asked to have the surface destroy deferred,
+ * it must call this once it is okay to destroy that surface.
+ */
+ void performDeferredDestroy(IWindow window);
+
+ /**
* Called by a client to report that it ran out of graphics memory.
*/
boolean outOfMemory(IWindow window);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 6c3d387..f53e42c 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -579,8 +579,20 @@ public class KeyEvent extends InputEvent implements Parcelable {
/** Key code constant: 3D Mode key.
* Toggles the display between 2D and 3D mode. */
public static final int KEYCODE_3D_MODE = 206;
-
- private static final int LAST_KEYCODE = KEYCODE_BUTTON_16;
+ /** Key code constant: Contacts special function key.
+ * Used to launch an address book application. */
+ public static final int KEYCODE_CONTACTS = 207;
+ /** Key code constant: Calendar special function key.
+ * Used to launch a calendar application. */
+ public static final int KEYCODE_CALENDAR = 208;
+ /** Key code constant: Music special function key.
+ * Used to launch a music player application. */
+ public static final int KEYCODE_MUSIC = 209;
+ /** Key code constant: Calculator special function key.
+ * Used to launch a calculator application. */
+ public static final int KEYCODE_CALCULATOR = 210;
+
+ private static final int LAST_KEYCODE = KEYCODE_CALCULATOR;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
@@ -589,6 +601,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
// external/webkit/WebKit/android/plugins/ANPKeyCodes.h
// frameworks/base/core/res/res/values/attrs.xml
// emulator?
+ // LAST_KEYCODE
+ // KEYCODE_SYMBOLIC_NAMES
//
// Also Android currently does not reserve code ranges for vendor-
// specific key codes. If you have new key codes to have, you
@@ -807,6 +821,10 @@ public class KeyEvent extends InputEvent implements Parcelable {
names.append(KEYCODE_LANGUAGE_SWITCH, "KEYCODE_LANGUAGE_SWITCH");
names.append(KEYCODE_MANNER_MODE, "KEYCODE_MANNER_MODE");
names.append(KEYCODE_3D_MODE, "KEYCODE_3D_MODE");
+ names.append(KEYCODE_CONTACTS, "KEYCODE_CONTACTS");
+ names.append(KEYCODE_CALENDAR, "KEYCODE_CALENDAR");
+ names.append(KEYCODE_MUSIC, "KEYCODE_MUSIC");
+ names.append(KEYCODE_CALCULATOR, "KEYCODE_CALCULATOR");
};
// Symbolic names of all metakeys in bit order from least significant to most significant.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 9a57ea0..0e68490 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,7 +16,6 @@
package android.view;
-import android.util.DisplayMetrics;
import com.android.internal.view.BaseIWindow;
import android.content.Context;
@@ -82,7 +81,6 @@ import java.util.concurrent.locks.ReentrantLock;
public class SurfaceView extends View {
static private final String TAG = "SurfaceView";
static private final boolean DEBUG = false;
- static private final boolean localLOGV = DEBUG ? true : false;
final ArrayList<SurfaceHolder.Callback> mCallbacks
= new ArrayList<SurfaceHolder.Callback>();
@@ -90,7 +88,8 @@ public class SurfaceView extends View {
final int[] mLocation = new int[2];
final ReentrantLock mSurfaceLock = new ReentrantLock();
- final Surface mSurface = new Surface();
+ Surface mSurface = new Surface(); // Current surface in use
+ Surface mNewSurface = new Surface(); // New surface we are switching to
boolean mDrawingStopped = true;
final WindowManager.LayoutParams mLayout
@@ -145,8 +144,7 @@ public class SurfaceView extends View {
int mRequestedFormat = PixelFormat.RGB_565;
boolean mHaveFrame = false;
- boolean mDestroyReportNeeded = false;
- boolean mNewSurfaceNeeded = false;
+ boolean mSurfaceCreated = false;
long mLastLockTime = 0;
boolean mVisible = false;
@@ -236,46 +234,6 @@ public class SurfaceView extends View {
updateWindow(false, false);
}
- /**
- * This method is not intended for general use. It was created
- * temporarily to improve performance of 3D layers in Launcher
- * and should be removed and fixed properly.
- *
- * Do not call this method. Ever.
- *
- * @hide
- */
- protected void showSurface() {
- if (mSession != null) {
- updateWindow(true, false);
- }
- }
-
- /**
- * This method is not intended for general use. It was created
- * temporarily to improve performance of 3D layers in Launcher
- * and should be removed and fixed properly.
- *
- * Do not call this method. Ever.
- *
- * @hide
- */
- protected void hideSurface() {
- if (mSession != null && mWindow != null) {
- mSurfaceLock.lock();
- try {
- DisplayMetrics metrics = getResources().getDisplayMetrics();
- mLayout.x = metrics.widthPixels * 3;
- mSession.relayout(mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, VISIBLE, false,
- mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurface);
- } catch (RemoteException e) {
- // Ignore
- } finally {
- mSurfaceLock.unlock();
- }
- }
- }
-
@Override
protected void onDetachedFromWindow() {
if (mGlobalListenersAdded) {
@@ -444,14 +402,13 @@ public class SurfaceView extends View {
final boolean creating = mWindow == null;
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
- final boolean visibleChanged = mVisible != mRequestedVisible
- || mNewSurfaceNeeded;
+ final boolean visibleChanged = mVisible != mRequestedVisible;
if (force || creating || formatChanged || sizeChanged || visibleChanged
|| mLeft != mLocation[0] || mTop != mLocation[1]
|| mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
- if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
+ if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
+ " visible=" + visibleChanged
+ " left=" + (mLeft != mLocation[0])
@@ -496,15 +453,11 @@ public class SurfaceView extends View {
mVisible ? VISIBLE : GONE, mContentInsets);
}
- if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
- reportSurfaceDestroyed();
- }
-
- mNewSurfaceNeeded = false;
-
boolean realSizeChanged;
boolean reportDrawNeeded;
-
+
+ int relayoutResult;
+
mSurfaceLock.lock();
try {
mUpdateWindowNeeded = false;
@@ -512,17 +465,21 @@ public class SurfaceView extends View {
mReportDrawNeeded = false;
mDrawingStopped = !visible;
- final int relayoutResult = mSession.relayout(
+ if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
+
+ relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
- visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
- mVisibleInsets, mConfiguration, mSurface);
- if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+ visible ? VISIBLE : GONE,
+ WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY,
+ mWinFrame, mContentInsets,
+ mVisibleInsets, mConfiguration, mNewSurface);
+ if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
mReportDrawNeeded = true;
}
-
- if (localLOGV) Log.i(TAG, "New surface: " + mSurface
+
+ if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
+ ", vis=" + visible + ", frame=" + mWinFrame);
-
+
mSurfaceFrame.left = 0;
mSurfaceFrame.top = 0;
if (mTranslator == null) {
@@ -547,28 +504,54 @@ public class SurfaceView extends View {
try {
redrawNeeded |= creating | reportDrawNeeded;
- if (visible) {
- mDestroyReportNeeded = true;
+ SurfaceHolder.Callback callbacks[] = null;
- SurfaceHolder.Callback callbacks[];
- synchronized (mCallbacks) {
- callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
- mCallbacks.toArray(callbacks);
+ final boolean surfaceChanged =
+ (relayoutResult&WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED) != 0;
+ if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
+ mSurfaceCreated = false;
+ if (mSurface.isValid()) {
+ if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed");
+ callbacks = getSurfaceCallbacks();
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceDestroyed(mSurfaceHolder);
+ }
}
+ }
+
+ Surface tmpSurface = mSurface;
+ mSurface = mNewSurface;
+ mNewSurface = tmpSurface;
+ mNewSurface.release();
- if (visibleChanged) {
+ if (visible) {
+ if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
+ mSurfaceCreated = true;
mIsCreating = true;
+ if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
+ if (callbacks == null) {
+ callbacks = getSurfaceCallbacks();
+ }
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceCreated(mSurfaceHolder);
}
}
if (creating || formatChanged || sizeChanged
|| visibleChanged || realSizeChanged) {
+ if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
+ + " w=" + myWidth + " h=" + myHeight);
+ if (callbacks == null) {
+ callbacks = getSurfaceCallbacks();
+ }
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
}
}
if (redrawNeeded) {
+ if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
+ if (callbacks == null) {
+ callbacks = getSurfaceCallbacks();
+ }
for (SurfaceHolder.Callback c : callbacks) {
if (c instanceof SurfaceHolder.Callback2) {
((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
@@ -576,41 +559,34 @@ public class SurfaceView extends View {
}
}
}
- } else {
- mSurface.release();
}
} finally {
mIsCreating = false;
if (redrawNeeded) {
+ if (DEBUG) Log.i(TAG, "finishedDrawing");
mSession.finishDrawing(mWindow);
}
+ mSession.performDeferredDestroy(mWindow);
}
} catch (RemoteException ex) {
}
- if (localLOGV) Log.v(
+ if (DEBUG) Log.v(
TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
" w=" + mLayout.width + " h=" + mLayout.height +
", frame=" + mSurfaceFrame);
}
}
- private void reportSurfaceDestroyed() {
- if (mDestroyReportNeeded) {
- mDestroyReportNeeded = false;
- SurfaceHolder.Callback callbacks[];
- synchronized (mCallbacks) {
- callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
- mCallbacks.toArray(callbacks);
- }
- for (SurfaceHolder.Callback c : callbacks) {
- c.surfaceDestroyed(mSurfaceHolder);
- }
+ private SurfaceHolder.Callback[] getSurfaceCallbacks() {
+ SurfaceHolder.Callback callbacks[];
+ synchronized (mCallbacks) {
+ callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
+ mCallbacks.toArray(callbacks);
}
- super.onDetachedFromWindow();
+ return callbacks;
}
void handleGetNewSurface() {
- mNewSurfaceNeeded = true;
updateWindow(false, false);
}
@@ -636,7 +612,7 @@ public class SurfaceView extends View {
Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
SurfaceView surfaceView = mSurfaceView.get();
if (surfaceView != null) {
- if (localLOGV) Log.v(
+ if (DEBUG) Log.v(
"SurfaceView", surfaceView + " got resized: w=" +
w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
surfaceView.mSurfaceLock.lock();
@@ -754,7 +730,7 @@ public class SurfaceView extends View {
private final Canvas internalLockCanvas(Rect dirty) {
mSurfaceLock.lock();
- if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
+ if (DEBUG) Log.i(TAG, "Locking canvas... stopped="
+ mDrawingStopped + ", win=" + mWindow);
Canvas c = null;
@@ -774,7 +750,7 @@ public class SurfaceView extends View {
}
}
- if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
+ if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
if (c != null) {
mLastLockTime = SystemClock.uptimeMillis();
return c;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5f70a39..7f5b5be 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1216,7 +1216,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
disposeResizeBuffer();
boolean completed = false;
- HardwareCanvas canvas = null;
+ HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
+ HardwareCanvas layerCanvas = null;
try {
if (mResizeBuffer == null) {
mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
@@ -1225,12 +1226,12 @@ public final class ViewRootImpl extends Handler implements ViewParent,
mResizeBuffer.getHeight() != mHeight) {
mResizeBuffer.resize(mWidth, mHeight);
}
- canvas = mResizeBuffer.start(mAttachInfo.mHardwareCanvas);
- canvas.setViewport(mWidth, mHeight);
- canvas.onPreDraw(null);
- final int restoreCount = canvas.save();
+ layerCanvas = mResizeBuffer.start(hwRendererCanvas);
+ layerCanvas.setViewport(mWidth, mHeight);
+ layerCanvas.onPreDraw(null);
+ final int restoreCount = layerCanvas.save();
- canvas.drawColor(0xff000000, PorterDuff.Mode.SRC);
+ layerCanvas.drawColor(0xff000000, PorterDuff.Mode.SRC);
int yoff;
final boolean scrolling = mScroller != null
@@ -1242,27 +1243,27 @@ public final class ViewRootImpl extends Handler implements ViewParent,
yoff = mScrollY;
}
- canvas.translate(0, -yoff);
+ layerCanvas.translate(0, -yoff);
if (mTranslator != null) {
- mTranslator.translateCanvas(canvas);
+ mTranslator.translateCanvas(layerCanvas);
}
- mView.draw(canvas);
+ mView.draw(layerCanvas);
mResizeBufferStartTime = SystemClock.uptimeMillis();
mResizeBufferDuration = mView.getResources().getInteger(
com.android.internal.R.integer.config_mediumAnimTime);
completed = true;
- canvas.restoreToCount(restoreCount);
+ layerCanvas.restoreToCount(restoreCount);
} catch (OutOfMemoryError e) {
Log.w(TAG, "Not enough memory for content change anim buffer", e);
} finally {
- if (canvas != null) {
- canvas.onPostDraw();
+ if (layerCanvas != null) {
+ layerCanvas.onPostDraw();
}
if (mResizeBuffer != null) {
- mResizeBuffer.end(mAttachInfo.mHardwareCanvas);
+ mResizeBuffer.end(hwRendererCanvas);
if (!completed) {
mResizeBuffer.destroy();
mResizeBuffer = null;
@@ -1425,7 +1426,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (!mStopped) {
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
- (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
+ (relayoutResult&WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
|| mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
@@ -1636,7 +1637,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
mLastDrawDurationNanos = System.nanoTime() - drawStartTime;
}
- if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0
+ if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0
|| mReportNextDraw) {
if (LOCAL_LOGV) {
Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
@@ -1669,7 +1670,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
// We were supposed to report when we are done drawing. Since we canceled the
// draw, remember it here.
- if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+ if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
mReportNextDraw = true;
}
if (fullRedrawNeeded) {
@@ -3585,8 +3586,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
- viewVisibility, insetsPending, mWinFrame,
- mPendingContentInsets, mPendingVisibleInsets,
+ viewVisibility, insetsPending ? WindowManagerImpl.RELAYOUT_INSETS_PENDING : 0,
+ mWinFrame, mPendingContentInsets, mPendingVisibleInsets,
mPendingConfiguration, mSurface);
//Log.d(TAG, "<<<<<< BACK FROM relayout");
if (restore) {
@@ -3716,7 +3717,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
// animation info.
try {
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
- & WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+ & WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
sWindowSession.finishDrawing(mWindow);
}
} catch (RemoteException e) {
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index b657204..48fe0df 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -278,10 +278,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
}
private void createSliders() {
- final int silentableStreams = System.getInt(mContext.getContentResolver(),
- System.MODE_RINGER_STREAMS_AFFECTED,
- ((1 << AudioSystem.STREAM_NOTIFICATION) | (1 << AudioSystem.STREAM_RING)));
-
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mStreamControls = new HashMap<Integer, StreamControl>(STREAMS.length);
@@ -297,9 +293,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
sc.group.setTag(sc);
sc.icon = (ImageView) sc.group.findViewById(R.id.stream_icon);
- if ((silentableStreams & (1 << sc.streamType)) != 0) {
- sc.icon.setOnClickListener(this);
- }
sc.icon.setTag(sc);
sc.icon.setContentDescription(res.getString(streamRes.descRes));
sc.iconRes = streamRes.iconRes;
@@ -356,7 +349,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
&& mAudioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) {
sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate);
}
- sc.seekbarView.setEnabled(!muted);
}
private boolean isExpanded() {
@@ -436,8 +428,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
mAudioService.getLastAudibleStreamVolume(streamType)
: mAudioService.getStreamVolume(streamType);
-// int message = UNKNOWN_VOLUME_TEXT;
-// int additionalMessage = 0;
mRingIsSilent = false;
if (LOGD) {
@@ -697,18 +687,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
public void onClick(View v) {
if (v == mMoreButton) {
expand();
- } else if (v.getTag() instanceof StreamControl) {
- StreamControl sc = (StreamControl) v.getTag();
- boolean vibeInSilent = Settings.System.getInt(mContext.getContentResolver(),
- System.VIBRATE_IN_SILENT, 1) == 1;
- int newMode = mAudioManager.isSilentMode()
- ? AudioManager.RINGER_MODE_NORMAL
- : (vibeInSilent
- ? AudioManager.RINGER_MODE_VIBRATE
- : AudioManager.RINGER_MODE_SILENT);
- mAudioManager.setRingerMode(newMode);
- // Expand the dialog if it hasn't been expanded yet.
- if (mShowCombinedVolumes && !isExpanded()) expand();
}
resetTimeout();
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index dfd1d55..d711337 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -63,15 +63,34 @@ public class WindowManagerImpl implements WindowManager {
* The user is navigating with keys (not the touch screen), so
* navigational focus should be shown.
*/
- public static final int RELAYOUT_IN_TOUCH_MODE = 0x1;
+ public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1;
/**
* This is the first time the window is being drawn,
* so the client must call drawingFinished() when done
*/
- public static final int RELAYOUT_FIRST_TIME = 0x2;
-
+ public static final int RELAYOUT_RES_FIRST_TIME = 0x2;
+ /**
+ * The window manager has changed the surface from the last call.
+ */
+ public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
+
+ /**
+ * Flag for relayout: the client will be later giving
+ * internal insets; as a result, the window will not impact other window
+ * layouts until the insets are given.
+ */
+ public static final int RELAYOUT_INSETS_PENDING = 0x1;
+
+ /**
+ * Flag for relayout: the client may be currently using the current surface,
+ * so if it is to be destroyed as a part of the relayout the destroy must
+ * be deferred until later. The client will call performDeferredDestroy()
+ * when it is okay.
+ */
+ public static final int RELAYOUT_DEFER_SURFACE_DESTROY = 0x2;
+
public static final int ADD_FLAG_APP_VISIBLE = 0x2;
- public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_IN_TOUCH_MODE;
+ public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_RES_IN_TOUCH_MODE;
public static final int ADD_OKAY = 0;
public static final int ADD_BAD_APP_TOKEN = -1;
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 7bf0c83..91dcac8 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -16,7 +16,6 @@
package android.view.accessibility;
-import android.accessibilityservice.IAccessibilityServiceConnection;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -590,24 +589,6 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
}
/**
- * Sets the connection for interacting with the AccessibilityManagerService.
- *
- * @param connection The connection.
- *
- * @hide
- */
- @Override
- public void setConnection(IAccessibilityServiceConnection connection) {
- super.setConnection(connection);
- List<AccessibilityRecord> records = mRecords;
- final int recordCount = records.size();
- for (int i = 0; i < recordCount; i++) {
- AccessibilityRecord record = records.get(i);
- record.setConnection(connection);
- }
- }
-
- /**
* Sets if this instance is sealed.
*
* @param sealed Whether is sealed.
@@ -821,23 +802,19 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* @param parcel A parcel containing the state of a {@link AccessibilityEvent}.
*/
public void initFromParcel(Parcel parcel) {
- if (parcel.readInt() == 1) {
- mConnection = IAccessibilityServiceConnection.Stub.asInterface(
- parcel.readStrongBinder());
- }
- setSealed(parcel.readInt() == 1);
+ mSealed = (parcel.readInt() == 1);
mEventType = parcel.readInt();
mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
mEventTime = parcel.readLong();
+ mConnectionId = parcel.readInt();
readAccessibilityRecordFromParcel(this, parcel);
// Read the records.
final int recordCount = parcel.readInt();
for (int i = 0; i < recordCount; i++) {
AccessibilityRecord record = AccessibilityRecord.obtain();
- // Do this to write the connection only once.
- record.setConnection(mConnection);
readAccessibilityRecordFromParcel(record, parcel);
+ record.mConnectionId = mConnectionId;
mRecords.add(record);
}
}
@@ -875,16 +852,11 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* {@inheritDoc}
*/
public void writeToParcel(Parcel parcel, int flags) {
- if (mConnection == null) {
- parcel.writeInt(0);
- } else {
- parcel.writeInt(1);
- parcel.writeStrongBinder(mConnection.asBinder());
- }
parcel.writeInt(isSealed() ? 1 : 0);
parcel.writeInt(mEventType);
TextUtils.writeToParcel(mPackageName, parcel, 0);
parcel.writeLong(mEventTime);
+ parcel.writeInt(mConnectionId);
writeAccessibilityRecordToParcel(this, parcel, flags);
// Write the records.
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 25b980b..96653e5 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -21,6 +21,8 @@ import android.graphics.Rect;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.Log;
+import android.util.SparseArray;
import java.util.Collections;
import java.util.List;
@@ -61,6 +63,12 @@ import java.util.concurrent.atomic.AtomicInteger;
public final class AccessibilityInteractionClient
extends IAccessibilityInteractionConnectionCallback.Stub {
+ public static final int NO_ID = -1;
+
+ private static final String LOG_TAG = "AccessibilityInteractionClient";
+
+ private static final boolean DEBUG = false;
+
private static final long TIMEOUT_INTERACTION_MILLIS = 5000;
private static final Object sStaticLock = new Object();
@@ -83,6 +91,10 @@ public final class AccessibilityInteractionClient
private final Rect mTempBounds = new Rect();
+ // The connection cache is shared between all interrogating threads.
+ private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
+ new SparseArray<IAccessibilityServiceConnection>();
+
/**
* @return The singleton of this class.
*/
@@ -111,28 +123,37 @@ public final class AccessibilityInteractionClient
/**
* Finds an {@link AccessibilityNodeInfo} by accessibility id.
*
- * @param connection A connection for interacting with the system.
+ * @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId A unique window id.
* @param accessibilityViewId A unique View accessibility id.
* @return An {@link AccessibilityNodeInfo} if found, null otherwise.
*/
- public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
- IAccessibilityServiceConnection connection, int accessibilityWindowId,
- int accessibilityViewId) {
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId,
+ int accessibilityWindowId, int accessibilityViewId) {
try {
- final int interactionId = mInteractionIdCounter.getAndIncrement();
- final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId(
- accessibilityWindowId, accessibilityViewId, interactionId, this,
- Thread.currentThread().getId());
- // If the scale is zero the call has failed.
- if (windowScale > 0) {
- AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
- interactionId);
- finalizeAccessibilityNodeInfo(info, connection, windowScale);
- return info;
+ IAccessibilityServiceConnection connection = getConnection(connectionId);
+ if (connection != null) {
+ final int interactionId = mInteractionIdCounter.getAndIncrement();
+ final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId(
+ accessibilityWindowId, accessibilityViewId, interactionId, this,
+ Thread.currentThread().getId());
+ // If the scale is zero the call has failed.
+ if (windowScale > 0) {
+ AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
+ interactionId);
+ finalizeAccessibilityNodeInfo(info, connectionId, windowScale);
+ return info;
+ }
+ } else {
+ if (DEBUG) {
+ Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
+ }
}
} catch (RemoteException re) {
- /* ignore */
+ if (DEBUG) {
+ Log.w(LOG_TAG, "Error while calling remote"
+ + " findAccessibilityNodeInfoByAccessibilityId", re);
+ }
}
return null;
}
@@ -141,25 +162,36 @@ public final class AccessibilityInteractionClient
* Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
* in the currently active window and starts from the root View in the window.
*
- * @param connection A connection for interacting with the system.
+ * @param connectionId The id of a connection for interacting with the system.
* @param viewId The id of the view.
* @return An {@link AccessibilityNodeInfo} if found, null otherwise.
*/
- public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(
- IAccessibilityServiceConnection connection, int viewId) {
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int connectionId,
+ int viewId) {
try {
- final int interactionId = mInteractionIdCounter.getAndIncrement();
- final float windowScale = connection.findAccessibilityNodeInfoByViewIdInActiveWindow(
- viewId, interactionId, this, Thread.currentThread().getId());
- // If the scale is zero the call has failed.
- if (windowScale > 0) {
- AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
- interactionId);
- finalizeAccessibilityNodeInfo(info, connection, windowScale);
- return info;
+ IAccessibilityServiceConnection connection = getConnection(connectionId);
+ if (connection != null) {
+ final int interactionId = mInteractionIdCounter.getAndIncrement();
+ final float windowScale =
+ connection.findAccessibilityNodeInfoByViewIdInActiveWindow(viewId,
+ interactionId, this, Thread.currentThread().getId());
+ // If the scale is zero the call has failed.
+ if (windowScale > 0) {
+ AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
+ interactionId);
+ finalizeAccessibilityNodeInfo(info, connectionId, windowScale);
+ return info;
+ }
+ } else {
+ if (DEBUG) {
+ Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
+ }
}
} catch (RemoteException re) {
- /* ignore */
+ if (DEBUG) {
+ Log.w(LOG_TAG, "Error while calling remote"
+ + " findAccessibilityNodeInfoByViewIdInActiveWindow", re);
+ }
}
return null;
}
@@ -169,25 +201,36 @@ public final class AccessibilityInteractionClient
* insensitive containment. The search is performed in the currently
* active window and starts from the root View in the window.
*
- * @param connection A connection for interacting with the system.
+ * @param connectionId The id of a connection for interacting with the system.
* @param text The searched text.
* @return A list of found {@link AccessibilityNodeInfo}s.
*/
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow(
- IAccessibilityServiceConnection connection, String text) {
+ int connectionId, String text) {
try {
- final int interactionId = mInteractionIdCounter.getAndIncrement();
- final float windowScale = connection.findAccessibilityNodeInfosByViewTextInActiveWindow(
- text, interactionId, this, Thread.currentThread().getId());
- // If the scale is zero the call has failed.
- if (windowScale > 0) {
- List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
- interactionId);
- finalizeAccessibilityNodeInfos(infos, connection, windowScale);
- return infos;
+ IAccessibilityServiceConnection connection = getConnection(connectionId);
+ if (connection != null) {
+ final int interactionId = mInteractionIdCounter.getAndIncrement();
+ final float windowScale =
+ connection.findAccessibilityNodeInfosByViewTextInActiveWindow(text,
+ interactionId, this, Thread.currentThread().getId());
+ // If the scale is zero the call has failed.
+ if (windowScale > 0) {
+ List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
+ interactionId);
+ finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
+ return infos;
+ }
+ } else {
+ if (DEBUG) {
+ Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
+ }
}
} catch (RemoteException re) {
- /* ignore */
+ if (DEBUG) {
+ Log.w(LOG_TAG, "Error while calling remote"
+ + " findAccessibilityNodeInfosByViewTextInActiveWindow", re);
+ }
}
return null;
}
@@ -198,30 +241,39 @@ public final class AccessibilityInteractionClient
* id is specified and starts from the View whose accessibility id is
* specified.
*
- * @param connection A connection for interacting with the system.
+ * @param connectionId The id of a connection for interacting with the system.
* @param text The searched text.
* @param accessibilityWindowId A unique window id.
* @param accessibilityViewId A unique View accessibility id from where to start the search.
* Use {@link android.view.View#NO_ID} to start from the root.
* @return A list of found {@link AccessibilityNodeInfo}s.
*/
- public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(
- IAccessibilityServiceConnection connection, String text, int accessibilityWindowId,
- int accessibilityViewId) {
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(int connectionId,
+ String text, int accessibilityWindowId, int accessibilityViewId) {
try {
- final int interactionId = mInteractionIdCounter.getAndIncrement();
- final float windowScale = connection.findAccessibilityNodeInfosByViewText(text,
- accessibilityWindowId, accessibilityViewId, interactionId, this,
- Thread.currentThread().getId());
- // If the scale is zero the call has failed.
- if (windowScale > 0) {
- List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
- interactionId);
- finalizeAccessibilityNodeInfos(infos, connection, windowScale);
- return infos;
+ IAccessibilityServiceConnection connection = getConnection(connectionId);
+ if (connection != null) {
+ final int interactionId = mInteractionIdCounter.getAndIncrement();
+ final float windowScale = connection.findAccessibilityNodeInfosByViewText(text,
+ accessibilityWindowId, accessibilityViewId, interactionId, this,
+ Thread.currentThread().getId());
+ // If the scale is zero the call has failed.
+ if (windowScale > 0) {
+ List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
+ interactionId);
+ finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
+ return infos;
+ }
+ } else {
+ if (DEBUG) {
+ Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
+ }
}
} catch (RemoteException re) {
- /* ignore */
+ if (DEBUG) {
+ Log.w(LOG_TAG, "Error while calling remote"
+ + " findAccessibilityNodeInfosByViewText", re);
+ }
}
return Collections.emptyList();
}
@@ -229,24 +281,33 @@ public final class AccessibilityInteractionClient
/**
* Performs an accessibility action on an {@link AccessibilityNodeInfo}.
*
- * @param connection A connection for interacting with the system.
+ * @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId The id of the window.
* @param accessibilityViewId A unique View accessibility id.
* @param action The action to perform.
* @return Whether the action was performed.
*/
- public boolean performAccessibilityAction(IAccessibilityServiceConnection connection,
- int accessibilityWindowId, int accessibilityViewId, int action) {
+ public boolean performAccessibilityAction(int connectionId, int accessibilityWindowId,
+ int accessibilityViewId, int action) {
try {
- final int interactionId = mInteractionIdCounter.getAndIncrement();
- final boolean success = connection.performAccessibilityAction(
- accessibilityWindowId, accessibilityViewId, action, interactionId, this,
- Thread.currentThread().getId());
- if (success) {
- return getPerformAccessibilityActionResult(interactionId);
+ IAccessibilityServiceConnection connection = getConnection(connectionId);
+ if (connection != null) {
+ final int interactionId = mInteractionIdCounter.getAndIncrement();
+ final boolean success = connection.performAccessibilityAction(
+ accessibilityWindowId, accessibilityViewId, action, interactionId, this,
+ Thread.currentThread().getId());
+ if (success) {
+ return getPerformAccessibilityActionResult(interactionId);
+ }
+ } else {
+ if (DEBUG) {
+ Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
+ }
}
} catch (RemoteException re) {
- /* ignore */
+ if (DEBUG) {
+ Log.w(LOG_TAG, "Error while calling remote performAccessibilityAction", re);
+ }
}
return false;
}
@@ -406,14 +467,14 @@ public final class AccessibilityInteractionClient
* Finalize an {@link AccessibilityNodeInfo} before passing it to the client.
*
* @param info The info.
- * @param connection The current connection to the system.
+ * @param connectionId The id of the connection to the system.
* @param windowScale The source window compatibility scale.
*/
- private void finalizeAccessibilityNodeInfo(AccessibilityNodeInfo info,
- IAccessibilityServiceConnection connection, float windowScale) {
+ private void finalizeAccessibilityNodeInfo(AccessibilityNodeInfo info, int connectionId,
+ float windowScale) {
if (info != null) {
applyCompatibilityScaleIfNeeded(info, windowScale);
- info.setConnection(connection);
+ info.setConnectionId(connectionId);
info.setSealed(true);
}
}
@@ -422,16 +483,16 @@ public final class AccessibilityInteractionClient
* Finalize {@link AccessibilityNodeInfo}s before passing them to the client.
*
* @param infos The {@link AccessibilityNodeInfo}s.
- * @param connection The current connection to the system.
+ * @param connectionId The id of the connection to the system.
* @param windowScale The source window compatibility scale.
*/
private void finalizeAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos,
- IAccessibilityServiceConnection connection, float windowScale) {
+ int connectionId, float windowScale) {
if (infos != null) {
final int infosCount = infos.size();
for (int i = 0; i < infosCount; i++) {
AccessibilityNodeInfo info = infos.get(i);
- finalizeAccessibilityNodeInfo(info, connection, windowScale);
+ finalizeAccessibilityNodeInfo(info, connectionId, windowScale);
}
}
}
@@ -449,4 +510,39 @@ public final class AccessibilityInteractionClient
return result;
}
}
+
+ /**
+ * Gets a cached accessibility service connection.
+ *
+ * @param connectionId The connection id.
+ * @return The cached connection if such.
+ */
+ public IAccessibilityServiceConnection getConnection(int connectionId) {
+ synchronized (sConnectionCache) {
+ return sConnectionCache.get(connectionId);
+ }
+ }
+
+ /**
+ * Adds a cached accessibility service connection.
+ *
+ * @param connectionId The connection id.
+ * @param connection The connection.
+ */
+ public void addConnection(int connectionId, IAccessibilityServiceConnection connection) {
+ synchronized (sConnectionCache) {
+ sConnectionCache.put(connectionId, connection);
+ }
+ }
+
+ /**
+ * Removes a cached accessibility service connection.
+ *
+ * @param connectionId The connection id.
+ */
+ public void removeConnection(int connectionId) {
+ synchronized (sConnectionCache) {
+ sConnectionCache.remove(connectionId);
+ }
+ }
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index fa34ee7..9b0f44a 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -16,7 +16,6 @@
package android.view.accessibility;
-import android.accessibilityservice.IAccessibilityServiceConnection;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
@@ -53,6 +52,8 @@ public class AccessibilityNodeInfo implements Parcelable {
private static final boolean DEBUG = false;
+ private static final int UNDEFINED = -1;
+
// Actions.
/**
@@ -107,9 +108,9 @@ public class AccessibilityNodeInfo implements Parcelable {
private boolean mSealed;
// Data.
- private int mAccessibilityViewId = View.NO_ID;
- private int mAccessibilityWindowId = View.NO_ID;
- private int mParentAccessibilityViewId = View.NO_ID;
+ private int mAccessibilityViewId = UNDEFINED;
+ private int mAccessibilityWindowId = UNDEFINED;
+ private int mParentAccessibilityViewId = UNDEFINED;
private int mBooleanProperties;
private final Rect mBoundsInParent = new Rect();
private final Rect mBoundsInScreen = new Rect();
@@ -122,7 +123,7 @@ public class AccessibilityNodeInfo implements Parcelable {
private SparseIntArray mChildAccessibilityIds = new SparseIntArray();
private int mActions;
- private IAccessibilityServiceConnection mConnection;
+ private int mConnectionId = UNDEFINED;
/**
* Hide constructor from clients.
@@ -181,7 +182,7 @@ public class AccessibilityNodeInfo implements Parcelable {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnection,
+ return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
mAccessibilityWindowId, childAccessibilityViewId);
}
@@ -253,7 +254,7 @@ public class AccessibilityNodeInfo implements Parcelable {
return false;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.performAccessibilityAction(mConnection, mAccessibilityWindowId,
+ return client.performAccessibilityAction(mConnectionId, mAccessibilityWindowId,
mAccessibilityViewId, action);
}
@@ -277,7 +278,7 @@ public class AccessibilityNodeInfo implements Parcelable {
return Collections.emptyList();
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfosByViewText(mConnection, text,
+ return client.findAccessibilityNodeInfosByViewText(mConnectionId, text,
mAccessibilityWindowId, mAccessibilityViewId);
}
@@ -297,7 +298,7 @@ public class AccessibilityNodeInfo implements Parcelable {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnection,
+ return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
mAccessibilityWindowId, mParentAccessibilityViewId);
}
@@ -755,15 +756,16 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
- * Sets the connection for interacting with the system.
+ * Sets the unique id of the IAccessibilityServiceConnection over which
+ * this instance can send requests to the system.
*
- * @param connection The client token.
+ * @param connectionId The connection id.
*
* @hide
*/
- public final void setConnection(IAccessibilityServiceConnection connection) {
+ public void setConnectionId(int connectionId) {
enforceNotSealed();
- mConnection = connection;
+ mConnectionId = connectionId;
}
/**
@@ -900,16 +902,11 @@ public class AccessibilityNodeInfo implements Parcelable {
* </p>
*/
public void writeToParcel(Parcel parcel, int flags) {
- if (mConnection == null) {
- parcel.writeInt(0);
- } else {
- parcel.writeInt(1);
- parcel.writeStrongBinder(mConnection.asBinder());
- }
parcel.writeInt(isSealed() ? 1 : 0);
parcel.writeInt(mAccessibilityViewId);
parcel.writeInt(mAccessibilityWindowId);
parcel.writeInt(mParentAccessibilityViewId);
+ parcel.writeInt(mConnectionId);
SparseIntArray childIds = mChildAccessibilityIds;
final int childIdsSize = childIds.size();
@@ -949,10 +946,10 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
private void init(AccessibilityNodeInfo other) {
mSealed = other.mSealed;
- mConnection = other.mConnection;
mAccessibilityViewId = other.mAccessibilityViewId;
mParentAccessibilityViewId = other.mParentAccessibilityViewId;
mAccessibilityWindowId = other.mAccessibilityWindowId;
+ mConnectionId = other.mConnectionId;
mBoundsInParent.set(other.mBoundsInParent);
mBoundsInScreen.set(other.mBoundsInScreen);
mPackageName = other.mPackageName;
@@ -970,14 +967,11 @@ public class AccessibilityNodeInfo implements Parcelable {
* @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
*/
private void initFromParcel(Parcel parcel) {
- if (parcel.readInt() == 1) {
- mConnection = IAccessibilityServiceConnection.Stub.asInterface(
- parcel.readStrongBinder());
- }
mSealed = (parcel.readInt() == 1);
mAccessibilityViewId = parcel.readInt();
mAccessibilityWindowId = parcel.readInt();
mParentAccessibilityViewId = parcel.readInt();
+ mConnectionId = parcel.readInt();
SparseIntArray childIds = mChildAccessibilityIds;
final int childrenSize = parcel.readInt();
@@ -1011,10 +1005,10 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
private void clear() {
mSealed = false;
- mConnection = null;
- mAccessibilityViewId = View.NO_ID;
- mParentAccessibilityViewId = View.NO_ID;
- mAccessibilityWindowId = View.NO_ID;
+ mAccessibilityViewId = UNDEFINED;
+ mParentAccessibilityViewId = UNDEFINED;
+ mAccessibilityWindowId = UNDEFINED;
+ mConnectionId = UNDEFINED;
mChildAccessibilityIds.clear();
mBoundsInParent.set(0, 0, 0, 0);
mBoundsInScreen.set(0, 0, 0, 0);
@@ -1048,9 +1042,8 @@ public class AccessibilityNodeInfo implements Parcelable {
}
private boolean canPerformRequestOverConnection(int accessibilityViewId) {
- return (mAccessibilityWindowId != View.NO_ID
- && accessibilityViewId != View.NO_ID
- && mConnection != null);
+ return (mConnectionId != UNDEFINED && mAccessibilityWindowId != UNDEFINED
+ && accessibilityViewId != UNDEFINED);
}
@Override
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index a4e0688..18d0f6f 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -16,7 +16,6 @@
package android.view.accessibility;
-import android.accessibilityservice.IAccessibilityServiceConnection;
import android.os.Parcelable;
import android.view.View;
@@ -78,8 +77,8 @@ public class AccessibilityRecord {
int mAddedCount= UNDEFINED;
int mRemovedCount = UNDEFINED;
- int mSourceViewId = View.NO_ID;
- int mSourceWindowId = View.NO_ID;
+ int mSourceViewId = UNDEFINED;
+ int mSourceWindowId = UNDEFINED;
CharSequence mClassName;
CharSequence mContentDescription;
@@ -87,7 +86,8 @@ public class AccessibilityRecord {
Parcelable mParcelableData;
final List<CharSequence> mText = new ArrayList<CharSequence>();
- IAccessibilityServiceConnection mConnection;
+
+ int mConnectionId = UNDEFINED;
/*
* Hide constructor.
@@ -108,8 +108,8 @@ public class AccessibilityRecord {
mSourceWindowId = source.getAccessibilityWindowId();
mSourceViewId = source.getAccessibilityViewId();
} else {
- mSourceWindowId = View.NO_ID;
- mSourceViewId = View.NO_ID;
+ mSourceWindowId = UNDEFINED;
+ mSourceViewId = UNDEFINED;
}
}
@@ -119,33 +119,21 @@ public class AccessibilityRecord {
* <strong>Note:</strong> It is a client responsibility to recycle the received info
* by calling {@link AccessibilityNodeInfo#recycle() AccessibilityNodeInfo#recycle()}
* to avoid creating of multiple instances.
- *
* </p>
* @return The info of the source.
*/
public AccessibilityNodeInfo getSource() {
enforceSealed();
- if (mSourceWindowId == View.NO_ID || mSourceViewId == View.NO_ID || mConnection == null) {
+ if (mConnectionId == UNDEFINED || mSourceWindowId == UNDEFINED
+ || mSourceViewId == UNDEFINED) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnection, mSourceWindowId,
+ return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mSourceWindowId,
mSourceViewId);
}
/**
- * Sets the connection for interacting with the AccessibilityManagerService.
- *
- * @param connection The connection.
- *
- * @hide
- */
- public void setConnection(IAccessibilityServiceConnection connection) {
- enforceNotSealed();
- mConnection = connection;
- }
-
- /**
* Gets the id of the window from which the event comes from.
*
* @return The window id.
@@ -561,6 +549,19 @@ public class AccessibilityRecord {
}
/**
+ * Sets the unique id of the IAccessibilityServiceConnection over which
+ * this instance can send requests to the system.
+ *
+ * @param connectionId The connection id.
+ *
+ * @hide
+ */
+ public void setConnectionId(int connectionId) {
+ enforceNotSealed();
+ mConnectionId = connectionId;
+ }
+
+ /**
* Sets if this instance is sealed.
*
* @param sealed Whether is sealed.
@@ -708,7 +709,7 @@ public class AccessibilityRecord {
mText.addAll(record.mText);
mSourceWindowId = record.mSourceWindowId;
mSourceViewId = record.mSourceViewId;
- mConnection = record.mConnection;
+ mConnectionId = record.mConnectionId;
}
/**
@@ -732,8 +733,9 @@ public class AccessibilityRecord {
mBeforeText = null;
mParcelableData = null;
mText.clear();
- mSourceViewId = View.NO_ID;
- mSourceWindowId = View.NO_ID;
+ mSourceViewId = UNDEFINED;
+ mSourceWindowId = UNDEFINED;
+ mConnectionId = UNDEFINED;
}
@Override
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index c621ff6..c3794be 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -49,5 +49,5 @@ interface IAccessibilityManager {
void removeAccessibilityInteractionConnection(IWindow windowToken);
- IAccessibilityServiceConnection registerEventListener(IEventListener client);
+ void registerEventListener(IEventListener client);
}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index d6e36bb..9fa5593 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -345,6 +345,11 @@ public final class CookieManager {
* a system private class.
*/
public synchronized void setCookie(WebAddress uri, String value) {
+ if (JniUtil.useChromiumHttpStack()) {
+ nativeSetCookie(uri.toString(), value, false);
+ return;
+ }
+
if (value != null && value.length() > MAX_COOKIE_LENGTH) {
return;
}
@@ -500,6 +505,10 @@ public final class CookieManager {
* is a system private class.
*/
public synchronized String getCookie(WebAddress uri) {
+ if (JniUtil.useChromiumHttpStack()) {
+ return nativeGetCookie(uri.toString(), false);
+ }
+
if (!mAcceptCookie || uri == null) {
return null;
}
@@ -573,6 +582,8 @@ public final class CookieManager {
* {@hide} Too late to release publically.
*/
public void waitForCookieOperationsToComplete() {
+ // Note that this function is applicable for both the java
+ // and native http stacks, and works correctly with either.
synchronized (this) {
while (pendingCookieOperations > 0) {
try {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 877c9ea..24eebd7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -507,7 +507,7 @@ public class WebView extends AbsoluteLayout
private float mLastVelY;
// The id of the native layer being scrolled.
- private int mScrollingLayer;
+ private int mCurrentScrollingLayerId;
private Rect mScrollingLayerRect = new Rect();
// only trigger accelerated fling if the new velocity is at least
@@ -1306,8 +1306,15 @@ public class WebView extends AbsoluteLayout
if (AccessibilityManager.getInstance(mContext).isEnabled()
&& getSettings().getJavaScriptEnabled()) {
// exposing the TTS for now ...
- mTextToSpeech = new TextToSpeech(getContext(), null);
- addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE);
+ final Context ctx = getContext();
+ if (ctx != null) {
+ final String packageName = ctx.getPackageName();
+ if (packageName != null) {
+ mTextToSpeech = new TextToSpeech(getContext(), null, null,
+ packageName + ".**webview**");
+ addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE);
+ }
+ }
}
}
@@ -1628,6 +1635,14 @@ public class WebView extends AbsoluteLayout
clearTextEntry();
clearActionModes();
dismissFullScreenMode();
+ cancelSelectDialog();
+ }
+
+ private void cancelSelectDialog() {
+ if (mListBoxDialog != null) {
+ mListBoxDialog.cancel();
+ mListBoxDialog = null;
+ }
}
/**
@@ -3279,6 +3294,8 @@ public class WebView extends AbsoluteLayout
if (mNativeClass != 0) {
nativeSetPauseDrawing(mNativeClass, true);
}
+
+ cancelSelectDialog();
}
}
@@ -3648,7 +3665,7 @@ public class WebView extends AbsoluteLayout
if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) {
return;
}
- nativeScrollLayer(mScrollingLayer, x, y);
+ nativeScrollLayer(mCurrentScrollingLayerId, x, y);
mScrollingLayerRect.left = x;
mScrollingLayerRect.top = y;
onScrollChanged(mScrollX, mScrollY, mScrollX, mScrollY);
@@ -4453,6 +4470,7 @@ public class WebView extends AbsoluteLayout
Rect vBox = contentToViewRect(contentBounds);
Rect visibleRect = new Rect();
calcOurVisibleRect(visibleRect);
+ offsetByLayerScrollPosition(vBox);
// If the textfield is on screen, place the WebTextView in
// its new place, accounting for our new scroll/zoom values,
// and adjust its textsize.
@@ -4488,6 +4506,14 @@ public class WebView extends AbsoluteLayout
}
}
+ private void offsetByLayerScrollPosition(Rect box) {
+ if ((mCurrentScrollingLayerId != 0)
+ && (mCurrentScrollingLayerId == nativeFocusCandidateLayerId())) {
+ box.offsetTo(box.left - mScrollingLayerRect.left,
+ box.top - mScrollingLayerRect.top);
+ }
+ }
+
void setBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator,
boolean isPictureAfterFirstLayout, boolean registerPageSwapCallback) {
if (mNativeClass == 0)
@@ -4587,14 +4613,15 @@ public class WebView extends AbsoluteLayout
boolean UIAnimationsRunning = false;
// Currently for each draw we compute the animation values;
// We may in the future decide to do that independently.
- if (mNativeClass != 0 && nativeEvaluateLayersAnimations(mNativeClass)) {
+ if (mNativeClass != 0 && !canvas.isHardwareAccelerated()
+ && nativeEvaluateLayersAnimations(mNativeClass)) {
UIAnimationsRunning = true;
// If we have unfinished (or unstarted) animations,
// we ask for a repaint. We only need to do this in software
// rendering (with hardware rendering we already have a different
// method of requesting a repaint)
- if (!canvas.isHardwareAccelerated())
- invalidate();
+ mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED);
+ invalidate();
}
// decide which adornments to draw
@@ -4905,6 +4932,7 @@ public class WebView extends AbsoluteLayout
// should be in content coordinates.
Rect bounds = nativeFocusCandidateNodeBounds();
Rect vBox = contentToViewRect(bounds);
+ offsetByLayerScrollPosition(vBox);
mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), vBox.height());
if (!Rect.intersects(bounds, visibleRect)) {
revealSelection();
@@ -5496,10 +5524,10 @@ public class WebView extends AbsoluteLayout
mMaxAutoScrollX = getViewWidth();
mMinAutoScrollY = 0;
mMaxAutoScrollY = getViewHeightWithTitle();
- mScrollingLayer = nativeScrollableLayer(viewToContentX(mSelectX),
+ mCurrentScrollingLayerId = nativeScrollableLayer(viewToContentX(mSelectX),
viewToContentY(mSelectY), mScrollingLayerRect,
mScrollingLayerBounds);
- if (mScrollingLayer != 0) {
+ if (mCurrentScrollingLayerId != 0) {
if (mScrollingLayerRect.left != mScrollingLayerRect.right) {
mMinAutoScrollX = Math.max(mMinAutoScrollX,
contentToViewX(mScrollingLayerBounds.left));
@@ -5985,9 +6013,9 @@ public class WebView extends AbsoluteLayout
private void startScrollingLayer(float x, float y) {
int contentX = viewToContentX((int) x + mScrollX);
int contentY = viewToContentY((int) y + mScrollY);
- mScrollingLayer = nativeScrollableLayer(contentX, contentY,
+ mCurrentScrollingLayerId = nativeScrollableLayer(contentX, contentY,
mScrollingLayerRect, mScrollingLayerBounds);
- if (mScrollingLayer != 0) {
+ if (mCurrentScrollingLayerId != 0) {
mTouchMode = TOUCH_DRAG_LAYER_MODE;
}
}
@@ -6218,7 +6246,7 @@ public class WebView extends AbsoluteLayout
ted.mPointsInView[0] = new Point(x, y);
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
- ted.mNativeLayer = mScrollingLayer;
+ ted.mNativeLayer = mCurrentScrollingLayerId;
ted.mNativeLayerRect.set(mScrollingLayerRect);
ted.mSequence = mTouchEventQueue.nextTouchSequence();
mTouchEventQueue.preQueueTouchEventData(ted);
@@ -6409,7 +6437,7 @@ public class WebView extends AbsoluteLayout
ted.mPointsInView[0] = new Point(x, y);
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
- ted.mNativeLayer = mScrollingLayer;
+ ted.mNativeLayer = mCurrentScrollingLayerId;
ted.mNativeLayerRect.set(mScrollingLayerRect);
ted.mSequence = mTouchEventQueue.nextTouchSequence();
mTouchEventQueue.preQueueTouchEventData(ted);
@@ -6718,7 +6746,7 @@ public class WebView extends AbsoluteLayout
// directions. mTouchMode might be TOUCH_DRAG_MODE if we have
// reached the edge of a layer but mScrollingLayer will be non-zero
// if we initiated the drag on a layer.
- if (mScrollingLayer != 0) {
+ if (mCurrentScrollingLayerId != 0) {
final int contentX = viewToContentDimension(deltaX);
final int contentY = viewToContentDimension(deltaY);
@@ -7240,7 +7268,7 @@ public class WebView extends AbsoluteLayout
+ " vx=" + vx + " vy=" + vy
+ " maxX=" + maxX + " maxY=" + maxY
+ " scrollX=" + scrollX + " scrollY=" + scrollY
- + " layer=" + mScrollingLayer);
+ + " layer=" + mCurrentScrollingLayerId);
}
// Allow sloppy flings without overscrolling at the edges.
@@ -8349,7 +8377,7 @@ public class WebView extends AbsoluteLayout
mSentAutoScrollMessage = false;
break;
}
- if (mScrollingLayer == 0) {
+ if (mCurrentScrollingLayerId == 0) {
pinScrollBy(mAutoScrollX, mAutoScrollY, true, 0);
} else {
scrollLayerTo(mScrollingLayerRect.left + mAutoScrollX,
@@ -8779,10 +8807,13 @@ public class WebView extends AbsoluteLayout
/** @hide Called by JNI when pages are swapped (only occurs with hardware
* acceleration) */
- protected void pageSwapCallback() {
+ protected void pageSwapCallback(boolean notifyAnimationStarted) {
if (inEditingMode()) {
didUpdateWebTextViewDimensions(ANYWHERE);
}
+ if (notifyAnimationStarted) {
+ mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED);
+ }
}
void setNewPicture(final WebViewCore.DrawData draw, boolean updateBaseLayer) {
@@ -9560,6 +9591,7 @@ public class WebView extends AbsoluteLayout
* See WebTextView.setType()
*/
private native int nativeFocusCandidateType();
+ private native int nativeFocusCandidateLayerId();
private native boolean nativeFocusIsPlugin();
private native Rect nativeFocusNodeBounds();
/* package */ native int nativeFocusNodePointer();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 2ad866b..d136004 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -519,7 +519,12 @@ public final class WebViewCore {
/**
* Update the layers' content
*/
- private native boolean nativeUpdateLayers(int baseLayer);
+ private native boolean nativeUpdateLayers(int nativeClass, int baseLayer);
+
+ /**
+ * Notify webkit that animations have begun (on the hardware accelerated content)
+ */
+ private native void nativeNotifyAnimationStarted(int nativeClass);
private native boolean nativeFocusBoundsChanged();
@@ -1035,6 +1040,8 @@ public final class WebViewCore {
static final int PLUGIN_SURFACE_READY = 195;
+ static final int NOTIFY_ANIMATION_STARTED = 196;
+
// private message ids
private static final int DESTROY = 200;
@@ -1594,6 +1601,10 @@ public final class WebViewCore {
nativePluginSurfaceReady();
break;
+ case NOTIFY_ANIMATION_STARTED:
+ nativeNotifyAnimationStarted(mNativeClass);
+ break;
+
case ADD_PACKAGE_NAMES:
if (BrowserFrame.sJavaBridge == null) {
throw new IllegalStateException("No WebView " +
@@ -2015,7 +2026,7 @@ public final class WebViewCore {
return;
}
// Directly update the layers we last passed to the UI side
- if (nativeUpdateLayers(mLastDrawData.mBaseLayer)) {
+ if (nativeUpdateLayers(mNativeClass, mLastDrawData.mBaseLayer)) {
// If anything more complex than position has been touched, let's do a full draw
webkitDraw();
}
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 84d00c9..8c57265 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -493,11 +493,19 @@ class ZoomManager {
if (mHardwareAccelerated) {
mWebView.updateScrollCoordinates(mWebView.getScrollX() - tx, mWebView.getScrollY() - ty);
+ // By adding webView matrix, we need to offset the canvas a bit
+ // to make the animation smooth.
+ canvas.translate(tx, ty);
setZoomScale(zoomScale, false);
if (mZoomScale == 0) {
// We've reached the end of the zoom animation.
mInHWAcceleratedZoom = false;
+
+ // Ensure that the zoom level is pushed to WebCore. This has not
+ // yet occurred because we prevent it from happening while
+ // mInHWAcceleratedZoom is true.
+ mWebView.sendViewSizeZoom(false);
}
} else {
canvas.translate(tx, ty);
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 1a1b8d0..d185370 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -165,6 +165,11 @@ public class NumberPicker extends LinearLayout {
};
/**
+ * Constant for unspecified size.
+ */
+ private static final int SIZE_UNSPECIFIED = -1;
+
+ /**
* Use a custom NumberPicker formatting callback to use two-digit minutes
* strings like "01". Keeping a static formatter etc. is the most efficient
* way to do this; it avoids creating temporary objects on every call to
@@ -542,16 +547,20 @@ public class NumberPicker extends LinearLayout {
getResources().getDisplayMetrics());
mSelectionDividerHeight = attributesArray.getDimensionPixelSize(
R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight);
- mMinHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minHeight, 0);
+ mMinHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minHeight,
+ SIZE_UNSPECIFIED);
mMaxHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxHeight,
- Integer.MAX_VALUE);
- if (mMinHeight > mMaxHeight) {
+ SIZE_UNSPECIFIED);
+ if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED
+ && mMinHeight > mMaxHeight) {
throw new IllegalArgumentException("minHeight > maxHeight");
}
- mMinWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minWidth, 0);
+ mMinWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minWidth,
+ SIZE_UNSPECIFIED);
mMaxWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxWidth,
- Integer.MAX_VALUE);
- if (mMinWidth > mMaxWidth) {
+ SIZE_UNSPECIFIED);
+ if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED
+ && mMinWidth > mMaxWidth) {
throw new IllegalArgumentException("minWidth > maxWidth");
}
mComputeMaxWidth = (mMaxWidth == Integer.MAX_VALUE);
@@ -746,10 +755,10 @@ public class NumberPicker extends LinearLayout {
final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight);
super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
// Flag if we are measured with width or height less than the respective min.
- final int desiredWidth = Math.max(mMinWidth, getMeasuredWidth());
- final int desiredHeight = Math.max(mMinHeight, getMeasuredHeight());
- final int widthSize = resolveSizeAndState(desiredWidth, newWidthMeasureSpec, 0);
- final int heightSize = resolveSizeAndState(desiredHeight, newHeightMeasureSpec, 0);
+ final int widthSize = resolveSizeAndStateRespectingMinSize(mMinWidth, getMeasuredWidth(),
+ widthMeasureSpec);
+ final int heightSize = resolveSizeAndStateRespectingMinSize(mMinHeight, getMeasuredHeight(),
+ heightMeasureSpec);
setMeasuredDimension(widthSize, heightSize);
}
@@ -1243,6 +1252,7 @@ public class NumberPicker extends LinearLayout {
}
updateInputTextView();
initializeSelectorWheelIndices();
+ tryComputeMaxWidth();
}
@Override
@@ -1368,6 +1378,9 @@ public class NumberPicker extends LinearLayout {
* @return A measure spec greedily imposing the max size.
*/
private int makeMeasureSpec(int measureSpec, int maxSize) {
+ if (maxSize == SIZE_UNSPECIFIED) {
+ return measureSpec;
+ }
final int size = MeasureSpec.getSize(measureSpec);
final int mode = MeasureSpec.getMode(measureSpec);
switch (mode) {
@@ -1383,6 +1396,26 @@ public class NumberPicker extends LinearLayout {
}
/**
+ * Utility to reconcile a desired size and state, with constraints imposed by
+ * a MeasureSpec. Tries to respect the min size, unless a different size is
+ * imposed by the constraints.
+ *
+ * @param minSize The minimal desired size.
+ * @param measuredSize The currently measured size.
+ * @param measureSpec The current measure spec.
+ * @return The resolved size and state.
+ */
+ private int resolveSizeAndStateRespectingMinSize(int minSize, int measuredSize,
+ int measureSpec) {
+ if (minSize != SIZE_UNSPECIFIED) {
+ final int desiredWidth = Math.max(minSize, measuredSize);
+ return resolveSizeAndState(desiredWidth, measureSpec, 0);
+ } else {
+ return measuredSize;
+ }
+ }
+
+ /**
* Resets the selector indices and clear the cached
* string representation of these indices.
*/
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 185cfa9..bd03fb9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2581,6 +2581,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Returns whether the text is allowed to be wider than the View is.
+ * If false, the text will be wrapped to the width of the View.
+ *
+ * @attr ref android.R.styleable#TextView_scrollHorizontally
+ * @hide
+ */
+ public boolean getHorizontallyScrolling() {
+ return mHorizontallyScrolling;
+ }
+
+ /**
* Makes the TextView at least this many lines tall.
*
* Setting this value overrides any other (minimum) height setting. A single line TextView will
@@ -3816,7 +3827,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (imm != null && imm.isActive(this)) {
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
- clearFocus();
return;
}
}
@@ -3838,7 +3848,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
| KeyEvent.FLAG_EDITOR_ACTION)));
}
}
-
+
/**
* Set the private content type of the text, which is the
* {@link EditorInfo#privateImeOptions EditorInfo.privateImeOptions}
@@ -5594,8 +5604,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
outAttrs.extras = mInputContentType.extras;
} else {
outAttrs.imeOptions = EditorInfo.IME_NULL;
- // May not be defined otherwise and needed by onEditorAction
- mInputContentType = new InputContentType();
}
if (focusSearch(FOCUS_DOWN) != null) {
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT;
@@ -7613,6 +7621,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
list.get(i).onTextChanged(text, start, before, after);
}
}
+
+ updateSpellCheckSpans(start, start + after);
+
+ // Hide the controllers as soon as text is modified (typing, procedural...)
+ // We do not hide the span controllers, since they can be added when a new text is
+ // inserted into the text view (voice IME).
+ hideCursorControllers();
}
/**
@@ -7652,15 +7667,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
sendOnTextChanged(buffer, start, before, after);
onTextChanged(buffer, start, before, after);
-
- updateSpellCheckSpans(start, start + after);
-
- // Hide the controllers if the amount of content changed
- if (before != after) {
- // We do not hide the span controllers, as they can be added when a new text is
- // inserted into the text view
- hideCursorControllers();
- }
}
/**
@@ -7963,16 +7969,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void onClick(View view) {
if (view == mDeleteTextView) {
- deleteText();
- }
- }
-
- private void deleteText() {
- Editable editable = (Editable) mText;
- int start = editable.getSpanStart(mEasyEditSpan);
- int end = editable.getSpanEnd(mEasyEditSpan);
- if (start >= 0 && end >= 0) {
- editable.delete(start, end);
+ Editable editable = (Editable) mText;
+ int start = editable.getSpanStart(mEasyEditSpan);
+ int end = editable.getSpanEnd(mEasyEditSpan);
+ if (start >= 0 && end >= 0) {
+ deleteText_internal(start, end);
+ }
}
}
@@ -9096,7 +9098,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case ID_CUT:
setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
- ((Editable) mText).delete(min, max);
+ deleteText_internal(min, max);
stopSelectionActionMode();
return true;
@@ -9127,7 +9129,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) {
// Two spaces at beginning of paste: remove one
final int originalLength = mText.length();
- ((Editable) mText).delete(min - 1, min);
+ deleteText_internal(min - 1, min);
// Due to filters, there is no guarantee that exactly one character was
// removed: count instead.
final int delta = mText.length() - originalLength;
@@ -9137,7 +9139,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
!Character.isSpaceChar(charAfter) && charAfter != '\n') {
// No space at beginning of paste: add one
final int originalLength = mText.length();
- ((Editable) mText).replace(min, min, " ");
+ replaceText_internal(min, min, " ");
// Taking possible filters into account as above.
final int delta = mText.length() - originalLength;
min += delta;
@@ -9151,11 +9153,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) {
// Two spaces at end of paste: remove one
- ((Editable) mText).delete(max, max + 1);
+ deleteText_internal(max, max + 1);
} else if (!Character.isSpaceChar(charBefore) && charBefore != '\n' &&
!Character.isSpaceChar(charAfter) && charAfter != '\n') {
// No space at end of paste: add one
- ((Editable) mText).replace(max, max, " ");
+ replaceText_internal(max, max, " ");
}
}
}
@@ -9376,40 +9378,57 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mPositionY = mTempCoords[1];
}
- public boolean isVisible(int positionX, int positionY) {
- final TextView textView = TextView.this;
+ public void onScrollChanged() {
+ mScrollHasChanged = true;
+ }
+ }
- if (mTempRect == null) mTempRect = new Rect();
- final Rect clip = mTempRect;
- clip.left = getCompoundPaddingLeft();
- clip.top = getExtendedPaddingTop();
- clip.right = textView.getWidth() - getCompoundPaddingRight();
- clip.bottom = textView.getHeight() - getExtendedPaddingBottom();
-
- final ViewParent parent = textView.getParent();
- if (parent == null || !parent.getChildVisibleRect(textView, clip, null)) {
- return false;
- }
+ private boolean isPositionVisible(int positionX, int positionY) {
+ synchronized (sTmpPosition) {
+ final float[] position = sTmpPosition;
+ position[0] = positionX;
+ position[1] = positionY;
+ View view = this;
- int posX = mPositionX + positionX;
- int posY = mPositionY + positionY;
+ while (view != null) {
+ if (view != this) {
+ // Local scroll is already taken into account in positionX/Y
+ position[0] -= view.getScrollX();
+ position[1] -= view.getScrollY();
+ }
- // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal.
- return posX >= clip.left - 1 && posX <= clip.right + 1 &&
- posY >= clip.top && posY <= clip.bottom;
- }
+ if (position[0] < 0 || position[1] < 0 ||
+ position[0] > view.getWidth() || position[1] > view.getHeight()) {
+ return false;
+ }
- public boolean isOffsetVisible(int offset) {
- final int line = mLayout.getLineForOffset(offset);
- final int lineBottom = mLayout.getLineBottom(line);
- final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset);
- return isVisible(primaryHorizontal + viewportToContentHorizontalOffset(),
- lineBottom + viewportToContentVerticalOffset());
- }
+ if (!view.getMatrix().isIdentity()) {
+ view.getMatrix().mapPoints(position);
+ }
- public void onScrollChanged() {
- mScrollHasChanged = true;
+ position[0] += view.getLeft();
+ position[1] += view.getTop();
+
+ final ViewParent parent = view.getParent();
+ if (parent instanceof View) {
+ view = (View) parent;
+ } else {
+ // We've reached the ViewRoot, stop iterating
+ view = null;
+ }
+ }
}
+
+ // We've been able to walk up the view hierarchy and the position was never clipped
+ return true;
+ }
+
+ private boolean isOffsetVisible(int offset) {
+ final int line = mLayout.getLineForOffset(offset);
+ final int lineBottom = mLayout.getLineBottom(line);
+ final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset);
+ return isPositionVisible(primaryHorizontal + viewportToContentHorizontalOffset(),
+ lineBottom + viewportToContentVerticalOffset());
}
@Override
@@ -9510,7 +9529,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public void updatePosition(int parentPositionX, int parentPositionY,
boolean parentPositionChanged, boolean parentScrolled) {
// Either parentPositionChanged or parentScrolled is true, check if still visible
- if (isShowing() && getPositionListener().isOffsetVisible(getTextOffset())) {
+ if (isShowing() && isOffsetVisible(getTextOffset())) {
if (parentScrolled) computeLocalPosition();
updatePosition(parentPositionX, parentPositionY);
} else {
@@ -9867,9 +9886,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- TextView textView = (TextView) view;
Editable editable = (Editable) mText;
-
SuggestionInfo suggestionInfo = mSuggestionInfos[position];
if (suggestionInfo.suggestionIndex == DELETE_TEXT) {
@@ -9883,7 +9900,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) {
spanUnionEnd = spanUnionEnd + 1;
}
- editable.replace(spanUnionStart, spanUnionEnd, "");
+ deleteText_internal(spanUnionStart, spanUnionEnd);
}
hide();
return;
@@ -9904,6 +9921,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
// There is no way to know if the word was indeed added. Re-check.
+ // TODO The ExtractEditText should remove the span in the original text instead
editable.removeSpan(suggestionInfo.suggestionSpan);
updateSpellCheckSpans(spanStart, spanEnd);
} else {
@@ -9931,9 +9949,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int suggestionStart = suggestionInfo.suggestionStart;
final int suggestionEnd = suggestionInfo.suggestionEnd;
- final String suggestion = textView.getText().subSequence(
+ final String suggestion = suggestionInfo.text.subSequence(
suggestionStart, suggestionEnd).toString();
- editable.replace(spanStart, spanEnd, suggestion);
+ replaceText_internal(spanStart, spanEnd, suggestion);
// Notify source IME of the suggestion pick. Do this before swaping texts.
if (!TextUtils.isEmpty(
@@ -9957,6 +9975,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// way to assign them a valid range after replacement
if (suggestionSpansStarts[i] <= spanStart &&
suggestionSpansEnds[i] >= spanEnd) {
+ // TODO The ExtractEditText should restore these spans in the original text
editable.setSpan(suggestionSpans[i], suggestionSpansStarts[i],
suggestionSpansEnds[i] + lengthDifference, suggestionSpansFlags[i]);
}
@@ -10534,7 +10553,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return false;
}
- return getPositionListener().isVisible(mPositionX + mHotspotX, mPositionY);
+ return TextView.this.isPositionVisible(mPositionX + mHotspotX, mPositionY);
}
public abstract int getCurrentCursorOffset();
@@ -10823,7 +10842,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Handles can not cross and selection is at least one character
final int selectionEnd = getSelectionEnd();
- if (offset >= selectionEnd) offset = selectionEnd - 1;
+ if (offset >= selectionEnd) offset = Math.max(0, selectionEnd - 1);
positionAtCursorOffset(offset, false);
}
@@ -10865,7 +10884,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Handles can not cross and selection is at least one character
final int selectionStart = getSelectionStart();
- if (offset <= selectionStart) offset = selectionStart + 1;
+ if (offset <= selectionStart) offset = Math.min(selectionStart + 1, mText.length());
positionAtCursorOffset(offset, false);
}
@@ -11237,7 +11256,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
int max = extractRangeEndFromLong(minMax);
Selection.setSelection((Spannable) mText, max);
- ((Editable) mText).replace(min, max, content);
+ replaceText_internal(min, max, content);
if (dragDropIntoItself) {
int dragSourceStart = dragLocalState.start;
@@ -11250,7 +11269,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
// Delete original selection
- ((Editable) mText).delete(dragSourceStart, dragSourceEnd);
+ deleteText_internal(dragSourceStart, dragSourceEnd);
// Make sure we do not leave two adjacent spaces.
if ((dragSourceStart == 0 ||
@@ -11259,7 +11278,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Character.isSpaceChar(mTransformed.charAt(dragSourceStart)))) {
final int pos = dragSourceStart == mText.length() ?
dragSourceStart - 1 : dragSourceStart;
- ((Editable) mText).delete(pos, pos + 1);
+ deleteText_internal(pos, pos + 1);
}
}
}
@@ -11420,6 +11439,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ /**
+ * Deletes the range of text [start, end[.
+ * @hide
+ */
+ protected void deleteText_internal(int start, int end) {
+ ((Editable) mText).delete(start, end);
+ }
+
+ /**
+ * Replaces the range of text [start, end[ by replacement text
+ * @hide
+ */
+ protected void replaceText_internal(int start, int end, CharSequence text) {
+ ((Editable) mText).replace(start, end, text);
+ }
+
@ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
private CharSequence mTransformed;
@@ -11500,6 +11535,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private Path mHighlightPath;
private boolean mHighlightPathBogus = true;
private static final RectF sTempRect = new RectF();
+ private static final float[] sTmpPosition = new float[2];
// XXX should be much larger
private static final int VERY_WIDE = 1024*1024;
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 36f0246..72489a2 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -418,7 +418,7 @@ public class StateMachine {
public static final int SM_QUIT_CMD = -1;
/** Message.what value when initializing */
- public static final int SM_INIT_CMD = -1;
+ public static final int SM_INIT_CMD = -2;
/**
* Convenience constant that maybe returned by processMessage
@@ -569,6 +569,13 @@ public class StateMachine {
}
/**
+ * Clear the list of Processed Message Info.
+ */
+ void cleanup() {
+ mMessages.clear();
+ }
+
+ /**
* @return the information on a particular record. 0 is the oldest
* record and size()-1 is the newest record. If the index is to
* large null is returned.
@@ -608,6 +615,7 @@ public class StateMachine {
}
}
+
private static class SmHandler extends Handler {
/** The debug flag */
@@ -782,15 +790,8 @@ public class StateMachine {
*/
if (destState != null) {
if (destState == mQuittingState) {
- /**
- * We are quitting so ignore all messages.
- */
- mSm.quitting();
- if (mSm.mSmThread != null) {
- // If we made the thread then quit looper which stops the thread.
- getLooper().quit();
- mSm.mSmThread = null;
- }
+ cleanupAfterQuitting();
+
} else if (destState == mHaltingState) {
/**
* Call halting() if we've transitioned to the halting
@@ -803,6 +804,29 @@ public class StateMachine {
}
/**
+ * Cleanup all the static variables and the looper after the SM has been quit.
+ */
+ private final void cleanupAfterQuitting() {
+ mSm.quitting();
+ if (mSm.mSmThread != null) {
+ // If we made the thread then quit looper which stops the thread.
+ getLooper().quit();
+ mSm.mSmThread = null;
+ }
+
+ mSm.mSmHandler = null;
+ mSm = null;
+ mMsg = null;
+ mProcessedMessages.cleanup();
+ mStateStack = null;
+ mTempStateStack = null;
+ mStateInfo.clear();
+ mInitialState = null;
+ mDestState = null;
+ mDeferredMessages.clear();
+ }
+
+ /**
* Complete the construction of the state machine.
*/
private final void completeConstruction() {
diff --git a/core/res/res/anim/app_starting_exit.xml b/core/res/res/anim/app_starting_exit.xml
index ee8d80b..60e4109 100644
--- a/core/res/res/anim/app_starting_exit.xml
+++ b/core/res/res/anim/app_starting_exit.xml
@@ -18,7 +18,8 @@
*/
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/decelerate_quad">
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:detachWallpaper="true" android:interpolator="@interpolator/decelerate_quad">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="160" />
</set>
diff --git a/core/res/res/layout/date_picker.xml b/core/res/res/layout/date_picker.xml
index 6f0517d..9c1def2 100644
--- a/core/res/res/layout/date_picker.xml
+++ b/core/res/res/layout/date_picker.xml
@@ -32,7 +32,6 @@
<LinearLayout android:id="@+id/pickers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginRight="22dip"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="center">
@@ -77,7 +76,7 @@
android:id="@+id/calendar_view"
android:layout_width="245dip"
android:layout_height="280dip"
- android:layout_marginLeft="22dip"
+ android:layout_marginLeft="44dip"
android:layout_weight="1"
android:focusable="true"
android:focusableInTouchMode="true"
diff --git a/core/res/res/layout/global_actions_item.xml b/core/res/res/layout/global_actions_item.xml
index 67b1644..13ab985 100644
--- a/core/res/res/layout/global_actions_item.xml
+++ b/core/res/res/layout/global_actions_item.xml
@@ -14,48 +14,46 @@
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!-- RelativeLayouts have an issue enforcing minimum heights, so just
+ work around this for now with LinearLayouts. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:orientation="horizontal"
android:paddingLeft="11dip"
android:paddingTop="6dip"
android:paddingBottom="6dip"
>
-
<ImageView android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_alignParentTop="true"
- android:layout_alignParentBottom="true"
+ android:layout_gravity="center"
android:layout_marginRight="9dip"
- />
-
-
- <TextView android:id="@+id/status"
- android:layout_width="match_parent"
- android:layout_height="26dip"
-
- android:layout_toRightOf="@id/icon"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
-
- android:textAppearance="?android:attr/textAppearanceSmall"
/>
-
- <TextView android:id="@+id/message"
+ <LinearLayout
+ android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ >
+ <TextView android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+
+ android:gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
+ <TextView android:id="@+id/status"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:minHeight="26dp"
- android:layout_toRightOf="@id/icon"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_above="@id/status"
- android:layout_alignWithParentIfMissing="true"
- android:gravity="center_vertical"
- android:textAppearance="?android:attr/textAppearanceLarge"
- />
-
-
-</RelativeLayout>
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 42f3d8c..a5bb864 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -634,7 +634,7 @@
<string name="relationTypeParent" msgid="4755635567562925226">"Ouer"</string>
<string name="relationTypePartner" msgid="7266490285120262781">"Vennoot"</string>
<string name="relationTypeReferredBy" msgid="101573059844135524">"Verwys deur"</string>
- <string name="relationTypeRelative" msgid="1799819930085610271">"Relatief"</string>
+ <string name="relationTypeRelative" msgid="1799819930085610271">"Familielid"</string>
<string name="relationTypeSister" msgid="1735983554479076481">"Suster"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Eggenoot"</string>
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"Gepasmaakte"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 53c4f30..0ab7194 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -409,9 +409,9 @@
<string name="permlab_bindGadget" msgid="776905339015863471">"Widgets auswählen"</string>
<string name="permdesc_bindGadget" msgid="2098697834497452046">"Ermöglicht der App, dem System zu melden, welche Widgets von welcher Anwendung verwendet werden können. Mit dieser Berechtigung können Anwendungen anderen Anwendungen Zugriff auf persönliche Daten gewähren. Nicht für normale Apps vorgesehen."</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"Telefonstatus ändern"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Ermöglicht einer App, die Telefonfunktionen des Gerätes zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder die Mobilfunkverbindung des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
+ <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Ermöglicht einer App, die Telefonfunktionen des Geräts zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder die Mobilfunkverbindung des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
<string name="permlab_readPhoneState" msgid="2326172951448691631">"Telefonstatus lesen und identifizieren"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"Ermöglicht der App, auf die Telefonfunktionen des Gerätes zuzugreifen. Eine Anwendung mit dieser Berechtigung kann unter anderem bestimmen, welche Telefonnummer dieses Telefon verwendet, ob ein Anruf aktiv ist oder mit welcher Nummer der Anrufer verbunden ist."</string>
+ <string name="permdesc_readPhoneState" msgid="188877305147626781">"Ermöglicht der App, auf die Telefonfunktionen des Geräts zuzugreifen. Eine App mit dieser Berechtigung kann unter anderem bestimmen, welche Telefonnummer dieses Telefon verwendet, ob ein Anruf aktiv ist oder mit welcher Nummer der Anrufer verbunden ist."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Standby-Modus des Tablets deaktivieren"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Standby-Modus deaktivieren"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="4032181488045338551">"Ermöglicht einer App, den Standby-Modus des Tablets zu deaktivieren."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index db9dab0..fd91ee3 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -793,7 +793,7 @@
<string name="last_month" msgid="3959346739979055432">"El mes pasado"</string>
<string name="older" msgid="5211975022815554840">"Anterior"</string>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ayer"</item>
+ <item quantity="one" msgid="861358534398115820">"Ayer"</item>
<item quantity="other" msgid="2479586466153314633">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="in_num_seconds">
@@ -825,7 +825,7 @@
<item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ayer"</item>
+ <item quantity="one" msgid="8463161711492680309">"Ayer"</item>
<item quantity="other" msgid="3453342639616481191">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
@@ -919,10 +919,10 @@
<string name="screen_compat_mode_hint" msgid="2953716574198046484">"Vuelve a habilitar esta opción en Ajustes &gt; Aplicaciones &gt; Administrar aplicaciones."</string>
<string name="smv_application" msgid="295583804361236288">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode autoaplicable."</string>
<string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha infringido su política StrictMode autoaplicable."</string>
- <string name="android_upgrading_title" msgid="378740715658358071">"Actualizando Android..."</string>
- <string name="android_upgrading_apk" msgid="274409861603566003">"Optimizando aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+ <string name="android_upgrading_title" msgid="378740715658358071">"Actualizando Android"</string>
+ <string name="android_upgrading_apk" msgid="274409861603566003">"Optimizando aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>..."</string>
<string name="android_upgrading_starting_apps" msgid="7959542881906488763">"Iniciando aplicaciones"</string>
- <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalizando arranque"</string>
+ <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalizando inicio..."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
<string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Seleccionar para cambiar a la aplicación"</string>
<string name="heavy_weight_switcher_title" msgid="1135403633766694316">"¿Cambiar de aplicación?"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index f2726d8b..830bd69 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"O"</string>
+ <string name="byteShort" msgid="8340973892742019101">"o"</string>
<string name="kilobyteShort" msgid="5973789783504771878">"Ko"</string>
<string name="megabyteShort" msgid="6355851576770428922">"Mo"</string>
<string name="gigabyteShort" msgid="3259882455212193214">"Go"</string>
@@ -1219,6 +1219,6 @@
<string name="status_bar_device_locked" msgid="3092703448690669768">"Appareil verrouillé"</string>
<string name="list_delimeter" msgid="3975117572185494152">", "</string>
<string name="sending" msgid="8715108995741758718">"Envoi en cours…"</string>
- <string name="launchBrowserDefault" msgid="2057951947297614725">"Lancer l\'application Navigateur ?"</string>
+ <string name="launchBrowserDefault" msgid="2057951947297614725">"Lancer le navigateur ?"</string>
<string name="SetupCallDefault" msgid="6870275517518479651">"Prendre l\'appel ?"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 679d73d..022a520 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -51,7 +51,7 @@
<string name="needPuk" msgid="919668385956251611">"O seu cartão SIM está bloqueado com PUK. Introduza o código PUK para desbloqueá-lo."</string>
<string name="needPuk2" msgid="4526033371987193070">"Introduza o PUK2 para desbloquear o cartão SIM."</string>
<string name="ClipMmi" msgid="6952821216480289285">"ID do Autor da Chamada"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"ID do autor da chamada efectuada"</string>
+ <string name="ClirMmi" msgid="7784673673446833091">"ID do autor da chamada efetuada"</string>
<string name="CfMmi" msgid="5123218989141573515">"Encaminhamento de chamadas"</string>
<string name="CwMmi" msgid="9129678056795016867">"Chamada em espera"</string>
<string name="BaMmi" msgid="455193067926770581">"Barramento de chamadas"</string>
@@ -170,7 +170,7 @@
<string name="permgrouplab_accounts" msgid="3359646291125325519">"As suas contas"</string>
<string name="permgroupdesc_accounts" msgid="4948732641827091312">"Aceda às contas disponíveis."</string>
<string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controlos de hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Aceda directamente ao hardware no telefone."</string>
+ <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Aceda diretamente ao hardware no telefone."</string>
<string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Chamadas telefónicas"</string>
<string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitorize, grave e processe chamadas telefónicas."</string>
<string name="permgrouplab_systemTools" msgid="4652191644082714048">"Ferramentas do sistema"</string>
@@ -291,7 +291,7 @@
<string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Permite a uma aplicação eliminar ficheiros em cache."</string>
<string name="permlab_getPackageSize" msgid="4799785352306641460">"medir espaço de armazenamento da aplicação"</string>
<string name="permdesc_getPackageSize" msgid="5557253039670753437">"Permite a uma aplicação obter os respectivos código, dados e tamanhos de cache"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicações directamente"</string>
+ <string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicações diretamente"</string>
<string name="permdesc_installPackages" msgid="526669220850066132">"Permite a uma aplicação instalar pacotes novos ou actualizados do Android. Algumas aplicações maliciosas podem utilizar este item para adicionar novas aplicações com autorizações arbitrariamente fortes."</string>
<string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos os dados da aplicações"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Permite a uma aplicação libertar espaço de armazenamento no tablet eliminando ficheiros no directório da cache da aplicação. Geralmente, o acesso é muito limitado para processamento do sistema."</string>
@@ -395,12 +395,12 @@
<string name="permdesc_accessMtp" msgid="6532961200486791570">"Permite o acesso ao controlador MTP de kernel para implementar o protocolo MTP USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testar hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite à aplicação controlar vários periféricos para fins de teste de hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone directamente"</string>
+ <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone diretamente"</string>
<string name="permdesc_callPhone" msgid="3369867353692722456">"Permite à aplicação marcar números de telefone sem a intervenção do utilizador. Algumas aplicações maliciosas podem provocar o aparecimento de chamadas inesperadas na sua conta telefónica. Tenha em atenção que isto não permite à aplicação marcar números de emergência."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"marcar directamente quaisquer números de telefone"</string>
+ <string name="permlab_callPrivileged" msgid="4198349211108497879">"marcar diretamente quaisquer números de telefone"</string>
<string name="permdesc_callPrivileged" msgid="244405067160028452">"Permite à aplicação marcar qualquer número de telefone, incluindo números de emergência, sem a intervenção do utilizador. Algumas aplicações maliciosas podem efectuar chamadas desnecessárias e ilegais para serviços de emergência."</string>
- <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"iniciar directamente a configuração do tablet CDMA"</string>
- <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente a configuração do telefone CDMA"</string>
+ <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"iniciar diretamente a configuração do tablet CDMA"</string>
+ <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar diretamente a configuração do telefone CDMA"</string>
<string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"Permite que a aplicação inicie o aprovisionamento CDMA. As aplicações mal intencionadas podem iniciar o aprovisionamento CDMA desnecessariamente"</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar notificações de actualização de localização"</string>
<string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite a activação/desactivação de notificações de actualização de localização a partir do rádio. Não se destina a utilização por aplicações normais."</string>
@@ -463,7 +463,7 @@
<string name="permlab_changeWifiState" msgid="7280632711057112137">"alterar estado de Wi-Fi"</string>
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite a uma aplicação ligar e desligar de pontos de acesso de Wi-Fi, bem como efectuar alterações a redes Wi-Fi configuradas."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recepção Multicast Wi-Fi"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite que uma aplicação receba pacotes não enviados directamente para o dispositivo. Esta opção pode ser útil para descobrir serviços oferecidos na vizinhança. Utiliza mais energia do que o modo não multicast."</string>
+ <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite que uma aplicação receba pacotes não enviados diretamente para o dispositivo. Esta opção pode ser útil para descobrir serviços oferecidos na vizinhança. Utiliza mais energia do que o modo não multicast."</string>
<string name="permlab_accessWimaxState" msgid="2800410363171809280">"ver estado do WiMAX"</string>
<string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Permite a uma aplicação ver as informações acerca do estado do Wi-Fi."</string>
<string name="permlab_changeWimaxState" msgid="340465839241528618">"alterar estado do WiMAX"</string>
@@ -935,7 +935,7 @@
<string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string>
<string name="volume_music" msgid="5421651157138628171">"Volume de multimédia"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"A reproduzir através de Bluetooth"</string>
- <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"Toque silencioso seleccionado"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"Toque silencioso selecionado"</string>
<string name="volume_call" msgid="3941680041282788711">"Volume da chamada recebida"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume de chamada recebida em Bluetooth"</string>
<string name="volume_alarm" msgid="1985191616042689100">"Volume do alarme"</string>
@@ -1081,7 +1081,7 @@
<string name="vpn_text" msgid="1610714069627824309">"Toque para gerir a rede."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Ligado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerir a rede."</string>
<string name="upload_file" msgid="2897957172366730416">"Escolher ficheiro"</string>
- <string name="no_file_chosen" msgid="6363648562170759465">"Não foi seleccionado nenhum ficheiro"</string>
+ <string name="no_file_chosen" msgid="6363648562170759465">"Não foi selecionado nenhum ficheiro"</string>
<string name="reset" msgid="2448168080964209908">"Repor"</string>
<string name="submit" msgid="1602335572089911941">"Enviar"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Modo automóvel activado"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 58b027c..1224d77 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1189,7 +1189,7 @@
<string name="data_usage_warning_body" msgid="7217480745540055170">"Проверить трафик и настройки"</string>
<string name="data_usage_3g_limit_title" msgid="7093334419518706686">"Передача данных 2G/3G отключена"</string>
<string name="data_usage_4g_limit_title" msgid="7636489436819470761">"Передача данных 4G отключена"</string>
- <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Мобильный Интернет отключен"</string>
+ <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Моб. Интернет отключен"</string>
<string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Передача данных через Wi-Fi отключена"</string>
<string name="data_usage_limit_body" msgid="4313857592916426843">"Нажмите, чтобы включить"</string>
<string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Превышен лимита трафика 2G и 3G"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 5334bfc..5c69718 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -49,7 +49,7 @@
<string name="invalidPin" msgid="3850018445187475377">"Chapisha PIN ambayo ina nambari 4 hadi 8."</string>
<string name="invalidPuk" msgid="8761456210898036513">"Andika PUK ambayo ina urefu wa nambari 8 au zaidi."</string>
<string name="needPuk" msgid="919668385956251611">"Kadi yako ya SIM imefungwa na PUK. Anika msimbo wa PUK ili kuifungua."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Chapisha PUK2 ili kufungua kadi ya SIM."</string>
+ <string name="needPuk2" msgid="4526033371987193070">"Chapisha PUK2 ili kufungua SIM kadi."</string>
<string name="ClipMmi" msgid="6952821216480289285">"Kitambulisho cha Mpigaji wa Simu Inayoingia"</string>
<string name="ClirMmi" msgid="7784673673446833091">"ID ya Mpigaji simu Inayotoka nje"</string>
<string name="CfMmi" msgid="5123218989141573515">"Kusambaza simu"</string>
@@ -199,11 +199,11 @@
<string name="permlab_sendSmsNoConfirmation" msgid="4781483105951730228">"Tuma ujumbe wa SMS bila ya thibitisho"</string>
<string name="permdesc_sendSmsNoConfirmation" msgid="4477752891276276168">"Huruhusu programu kutuma ujumbe wa SMS. Programu hatari huenda zikagharimu pesa kwa kutuma ujumbe bila ya uthibitishaji wako."</string>
<string name="permlab_readSms" msgid="4085333708122372256">"soma SMS au MMS"</string>
- <string name="permdesc_readSms" product="tablet" msgid="5836710350295631545">"Huruhusu programu kusoma SMS zilizohifadhiwa kwenye kompyuta yako ndogo au kadi ya SIM. Huenda programu hasidi zikasoma SMS zako za siri."</string>
- <string name="permdesc_readSms" product="default" msgid="3002170087197294591">"Huruhusu programu kusoma ujumbe wa SMS uliohifadhiwa kwenye simu yako au kadi ya SIM. Programu mbaya za kompyuta huenda zikasoma ujumbe wako wa siri."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="5836710350295631545">"Huruhusu programu kusoma SMS zilizohifadhiwa kwenye kompyuta yako ndogo au SIM kadi. Huenda programu hasidi zikasoma SMS zako za siri."</string>
+ <string name="permdesc_readSms" product="default" msgid="3002170087197294591">"Huruhusu programu kusoma ujumbe wa SMS uliohifadhiwa kwenye simu yako au SIM kadi. Programu mbaya za kompyuta huenda zikasoma ujumbe wako wa siri."</string>
<string name="permlab_writeSms" msgid="6881122575154940744">"hariri SMS au MMS"</string>
- <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Huruhusu programu kuandika ujumbe wa SMS uliohifadhiwa kwenye kompyuta yako au kadi ya SIM. Huenda programu hasidi zikafuta ujumbe wako."</string>
- <string name="permdesc_writeSms" product="default" msgid="6299398896177548095">"Huruhusu programu kuandika kwa ujumbe wa SMS uliohifadhiwa kwenye simu yako au kadi ya SIM. Programu mbaya za kompyuta huenda zikafuta ujumbe wako."</string>
+ <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Huruhusu programu kuandika ujumbe wa SMS uliohifadhiwa kwenye kompyuta yako au SIM kadi. Huenda programu hasidi zikafuta ujumbe wako."</string>
+ <string name="permdesc_writeSms" product="default" msgid="6299398896177548095">"Huruhusu programu kuandika kwa ujumbe wa SMS uliohifadhiwa kwenye simu yako au SIM kadi. Programu mbaya za kompyuta huenda zikafuta ujumbe wako."</string>
<string name="permlab_receiveWapPush" msgid="8258226427716551388">"pokea WAP"</string>
<string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Huruhusu programu kupokea na kuchakata ujumbe wa WAP. Programu mbaya za kompyuta huenda zikafuatilia ujumbe wako au kuzifuta bila kukuonyesha."</string>
<string name="permlab_getTasks" msgid="5005277531132573353">"epua programu zinazoendeshwa"</string>
@@ -333,9 +333,9 @@
<string name="permlab_writeProfile" msgid="4679878325177177400">"andika kwenye data ya maelezo yako mafupi"</string>
<string name="permdesc_writeProfile" product="default" msgid="6431297330378229453">"Inaruhusu programu kubadilisha au kuongeza maelezo binafsi ya maelezo yako mafupi yaliyohifadhiwa kwenye kifaa chako, kama vile jina lako na maelezo ya anwani. Hii ina maanisha programu nyingine ziweze kukutambua na kutuma maelezo ya maelezo yako mafupi kwa wengine."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"soma mkondo wako wa kijamii"</string>
- <string name="permdesc_readSocialStream" product="default" msgid="6619997662735851111">"Inaruhusu programuramu kufikia na kulandanisha usasisho kutoka kwako na marafiki wako. Prog hasidi zinaweza kutumia hizi kusoma mawasiliano ya kibinafsi kati yako na marafiki wako kwenye mitandao ya kijamii."</string>
+ <string name="permdesc_readSocialStream" product="default" msgid="6619997662735851111">"Inaruhusu programu kufikia na kulandanisha usasisho kutoka kwako na marafiki wako. Prog hasidi zinaweza kutumia hizi kusoma mawasiliano ya kibinafsi kati yako na marafiki wako kwenye mitandao ya kijamii."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"andika kwa mkondo wako wa kijamii"</string>
- <string name="permdesc_writeSocialStream" product="default" msgid="2689083745826002521">"Inaruhusu programuramu kuonyesha usasisho ya kijamii kutoka kwa marafiki wako. Prog hasidi zinaweza kutumia hizi zikijifanya kuwa rafiki na kukuhadaa kuonyesha nenosiri au taarifa zingine za siri."</string>
+ <string name="permdesc_writeSocialStream" product="default" msgid="2689083745826002521">"Inaruhusu programu kuonyesha usasisho ya kijamii kutoka kwa marafiki wako. Prog hasidi zinaweza kutumia hizi zikijifanya kuwa rafiki na kukuhadaa kuonyesha nenosiri au taarifa zingine za siri."</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"soma matukio ya kalenda pamoja na maelezo ya siri"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="5665520896961671949">"Huruhusu programu kusoma matukio yote ya kalenda yaliyohifadhiwa kwenye kompyuta yako ndogo, pamoja na za marafiki au wafanyakazi wenza. Programu hasidi yenye kibali hiki kinaweza kuchukua maelezo ya kibinagsi kutoka kwa kalenda hizi bila ufahamu wa mmiliki."</string>
<string name="permdesc_readCalendar" product="default" msgid="2915879965326930312">"Huruhusu programu kusoma matukio yote ya kalenda yaliyohifadhiwa kwenye simu yako, pamoja na za marafiki au marafiki wenza. Programu hasidi yenye kibali hiki inaweza kuchukua maelezo ya kibinafsi kutoka kwa kalenda hizi bila ufahamu wa mmiliki."</string>
@@ -665,11 +665,11 @@
<string name="lockscreen_charged" msgid="4938930459620989972">"Imechajiwa."</string>
<string name="lockscreen_battery_short" msgid="3617549178603354656">"Kishika nafasi<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Unganisha chaja yako"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Hakuna kadi ya SIM."</string>
- <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Hakuna kadi ya SIM katika kompyuta ndogo."</string>
- <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Hakuna kadi ya SIM kwenye simu."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Tafadhali ingiza kadi ya SIM."</string>
- <string name="lockscreen_missing_sim_instructions_long" msgid="7138450788301444298">"Kadi ya SIM inakosekana au haisomekani. Tafadhali ingiza kadi ya SIM."</string>
+ <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Hakuna SIM kadi."</string>
+ <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Hakuna SIM kadi katika kompyuta ndogo."</string>
+ <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Hakuna SIM kadi kwenye simu."</string>
+ <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Tafadhali ingiza SIM kadi."</string>
+ <string name="lockscreen_missing_sim_instructions_long" msgid="7138450788301444298">"Kadi ya SIM inakosekana au haisomekani. Tafadhali ingiza SIM kadi."</string>
<string name="lockscreen_permanent_disabled_sim_instructions" msgid="1631853574702335453">"Kadi yako ya SIM imelemazwa kabisa. "\n" tafadhali wasiliana na mtoa huduma wako wa psiwaya ili kupata kadi nyingine ya SIM."</string>
<string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Kitufe cha awali cha wimbo"</string>
<string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Kitufe cha wimbo unaofuata"</string>
@@ -681,7 +681,7 @@
<string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Kadi ya SIM imefungwa na PUK."</string>
<string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Tafadhali angalia Mwongozo wa Mtumiaji au wasiliana na Huduma kwa Wateja."</string>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Kadi ya SIM imefungwa."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Inafungua kadi ya SIM..."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Inafungua SIM kadi..."</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Umechora vibaya ruwaza yako ya kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Tafadhali jaribu tena kati ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Haujaingiza nenosiri yako kwa usahihi mara<xliff:g id="NUMBER_0">%d</xliff:g>Tafadhali jaribu tena. "\n\n"baada ya sekunde<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Haujaingiza PIN yako kwa usahihi mara<xliff:g id="NUMBER_0">%d</xliff:g>tafadhali jaribu tena. "\n\n"baada ya sekunde<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
@@ -892,7 +892,7 @@
<string name="no" msgid="5141531044935541497">"Ghairi"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Zingatia"</string>
<string name="loading" msgid="1760724998928255250">"Inapakia..."</string>
- <string name="capital_on" msgid="1544682755514494298">"Mnamo"</string>
+ <string name="capital_on" msgid="1544682755514494298">"Washa"</string>
<string name="capital_off" msgid="6815870386972805832">"ZIMA"</string>
<string name="whichApplication" msgid="4533185947064773386">"Kamilisha kitendo kwa kutumia"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Tumia kama chaguo-msingi la kitendo hiki."</string>
@@ -976,7 +976,7 @@
<string name="sms_control_yes" msgid="2532062172402615953">"Sawa"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Ghairi"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Kadi ya SIM imeondolewa"</string>
- <string name="sim_removed_message" msgid="2333164559970958645">"mtandao wa simu hutapatika hadi uanzishe upya na kadi ya SIM halali iliyoingizwa."</string>
+ <string name="sim_removed_message" msgid="2333164559970958645">"mtandao wa simu hutapatika hadi uanzishe upya na SIM kadi halali iliyoingizwa."</string>
<string name="sim_done_button" msgid="827949989369963775">"Kwisha"</string>
<string name="sim_added_title" msgid="3719670512889674693">"Kadi ya SIM imeongezwa"</string>
<string name="sim_added_message" msgid="1209265974048554242">"Lazima uwashe upya kifaa chako ili kufikia mtandao wa simu."</string>
@@ -1152,7 +1152,7 @@
<string name="checkbox_not_checked" msgid="5174639551134444056">"haijakaguliwa"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"Iliyochaguliwa"</string>
<string name="radiobutton_not_selected" msgid="2908760184307722393">"Haijachaguliwa"</string>
- <string name="switch_on" msgid="551417728476977311">"Mnamo"</string>
+ <string name="switch_on" msgid="551417728476977311">"Washa"</string>
<string name="switch_off" msgid="7249798614327155088">"zima"</string>
<string name="togglebutton_pressed" msgid="4180411746647422233">"iliyobonyezwa"</string>
<string name="togglebutton_not_pressed" msgid="4495147725636134425">"Haijabonyezwa"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 8213008..c46e0e9 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -359,8 +359,8 @@
<string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Cho phép ứng dụng đọc nội dung của bộ đệm khung."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"thay đổi cài đặt âm thanh của bạn"</string>
<string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Cho phép ứng dụng sửa đổi cài đặt âm thanh chung chẳng hạn như âm lượng và định tuyến."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"ghi âm thanh"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Cho phép ứng dụng truy cập vào đường dẫn bản ghi âm thanh."</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"ghi âm"</string>
+ <string name="permdesc_recordAudio" msgid="6493228261176552356">"Cho phép ứng dụng truy cập vào đường dẫn bản ghi âm."</string>
<string name="permlab_camera" msgid="3616391919559751192">"chụp ảnh và quay video"</string>
<string name="permdesc_camera" msgid="6004878235852154239">"Cho phép ứng dụng chụp ảnh và quay video bằng máy ảnh. Quyền này cho phép ứng dụng thu thập ảnh mà máy ảnh chụp vào bất kỳ thời điểm nào."</string>
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"vô hiệu hóa vĩnh viễn máy tính bảng"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 12b1784..cc4ff67 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -319,7 +319,7 @@
<string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"开机时自动启动"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="7530977064379338199">"允许应用程序在系统完成启动后立即自行启动。这样会延长平板电脑的启动时间,而且如果应用程序一直运行,会降低平板电脑的整体速度。"</string>
<string name="permdesc_receiveBootCompleted" product="default" msgid="698336728415008796">"允许应用程序在系统完成启动后即自行启动。这样会延长手机的启动时间,而且如果应用程序一直运行,会降低手机的整体速度。"</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"发送置顶广播"</string>
+ <string name="permlab_broadcastSticky" msgid="7919126372606881614">"发送持久广播"</string>
<string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"允许应用程序发送顽固广播,这些广播在结束后仍会保留。恶意应用程序可借此让平板电脑耗用太多内存,从而降低其速度或稳定性。"</string>
<string name="permdesc_broadcastSticky" product="default" msgid="1920045289234052219">"允许应用程序发送顽固广播,这些广播在结束后仍会保留。恶意应用程序可能会借此使手机耗用太多内存,从而降低其速度或稳定性。"</string>
<string name="permlab_readContacts" msgid="6219652189510218240">"读取联系人数据"</string>
@@ -904,9 +904,9 @@
<string name="aerr_application" msgid="932628488013092776">"很抱歉,“<xliff:g id="APPLICATION">%1$s</xliff:g>”已停止运行。"</string>
<string name="aerr_process" msgid="4507058997035697579">"抱歉,进程“<xliff:g id="PROCESS">%1$s</xliff:g>”已停止运行。"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
- <string name="anr_activity_application" msgid="8339738283149696827">"“<xliff:g id="APPLICATION">%2$s</xliff:g>”无响应。"\n\n"要将它关闭吗?"</string>
- <string name="anr_activity_process" msgid="7018289416670457797">"活动“<xliff:g id="ACTIVITY">%1$s</xliff:g>”无响应。"\n\n"要将它关闭吗?"</string>
- <string name="anr_application_process" msgid="7208175830253210526">"“<xliff:g id="APPLICATION">%1$s</xliff:g>”无响应。要将它关闭吗?"</string>
+ <string name="anr_activity_application" msgid="8339738283149696827">"<xliff:g id="APPLICATION">%2$s</xliff:g> 无响应。"\n\n"要将它关闭吗?"</string>
+ <string name="anr_activity_process" msgid="7018289416670457797">"活动 <xliff:g id="ACTIVITY">%1$s</xliff:g> 无响应。"\n\n"要将它关闭吗?"</string>
+ <string name="anr_application_process" msgid="7208175830253210526">"<xliff:g id="APPLICATION">%1$s</xliff:g> 无响应。要将它关闭吗?"</string>
<string name="anr_process" msgid="306819947562555821">"进程 <xliff:g id="PROCESS">%1$s</xliff:g> 无响应。"\n\n"要将它关闭吗?"</string>
<string name="force_close" msgid="8346072094521265605">"确定"</string>
<string name="report" msgid="4060218260984795706">"报告"</string>
@@ -1181,7 +1181,7 @@
<string name="action_bar_home_description" msgid="5293600496601490216">"导航首页"</string>
<string name="action_bar_up_description" msgid="2237496562952152589">"向上导航"</string>
<string name="action_menu_overflow_description" msgid="2295659037509008453">"更多选项"</string>
- <string name="storage_internal" msgid="7556050805474115618">"内存空间"</string>
+ <string name="storage_internal" msgid="7556050805474115618">"内部存储空间"</string>
<string name="storage_sd_card" msgid="8921771478629812343">"SD 卡"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB 存储器"</string>
<string name="extract_edit_menu_button" msgid="302060189057163906">"编辑..."</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 1252ba1..20b353d 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1219,6 +1219,6 @@
<string name="status_bar_device_locked" msgid="3092703448690669768">"裝置已鎖定。"</string>
<string name="list_delimeter" msgid="3975117572185494152">"、 "</string>
<string name="sending" msgid="8715108995741758718">"傳送中..."</string>
- <string name="launchBrowserDefault" msgid="2057951947297614725">"要啟動「瀏覽器」嗎?"</string>
- <string name="SetupCallDefault" msgid="6870275517518479651">"要接受通話嗎?"</string>
+ <string name="launchBrowserDefault" msgid="2057951947297614725">"啟動「瀏覽器」嗎?"</string>
+ <string name="SetupCallDefault" msgid="6870275517518479651">"接聽電話嗎?"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index eb9e660..0345bf0 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -698,7 +698,7 @@
<string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Ukuvula, ngena ngemvumekwi-akhawunti ye-Google"</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Igama lomsebenzisi (i-imeyli)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Iphasiwedi"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Ngena ngemvume"</string>
+ <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Ngena"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Igama lomsebezisi elingalungile noma iphasiwedi."</string>
<string name="lockscreen_glogin_account_recovery_hint" msgid="8253152905532900548">"Ukhohlwe igama lomsebenzisi noma iphasiwedi?"\n"Vakashela"<b>"google.com/accounts/recovery"</b></string>
<string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Iyahlola..."</string>
@@ -768,8 +768,8 @@
<string name="menu_enter_shortcut_label" msgid="2743362785111309668">"faka"</string>
<string name="menu_delete_shortcut_label" msgid="3658178007202748164">"susa"</string>
<string name="search_go" msgid="8298016669822141719">"Sesha"</string>
- <string name="searchview_description_search" msgid="6749826639098512120">"Cinga"</string>
- <string name="searchview_description_query" msgid="5911778593125355124">"Cinga umbuzo"</string>
+ <string name="searchview_description_search" msgid="6749826639098512120">"Sesha"</string>
+ <string name="searchview_description_query" msgid="5911778593125355124">"Umbuzo wosesho"</string>
<string name="searchview_description_clear" msgid="1330281990951833033">"xazulula umbuzo"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Thumela umbuzo"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Ukusesha ngezwi"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d0ab8b1..af59198 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1493,6 +1493,10 @@
<enum name="KEYCODE_LANGUAGE_SWITCH" value="204" />
<enum name="KEYCODE_MANNER_MODE" value="205" />
<enum name="KEYCODE_3D_MODE" value="206" />
+ <enum name="KEYCODE_CONTACTS" value="207" />
+ <enum name="KEYCODE_CALENDAR" value="208" />
+ <enum name="KEYCODE_MUSIC" value="209" />
+ <enum name="KEYCODE_CALCULATOR" value="210" />
</attr>
<!-- ***************************************************************** -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 25f7d25..767cafe 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -741,7 +741,4 @@
<string name="config_wimaxServiceClassname"></string>
<!-- Name of the wimax state tracker clas -->
<string name="config_wimaxStateTrackerClassname"></string>
-
- <!-- Name of screensaver components to look for if none has been chosen by the user -->
- <string name="config_defaultDreamComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
</resources>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
index d23dfd3..3ffa085 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
@@ -38,7 +38,8 @@ public class ConnectivityManagerStressTestRunner extends InstrumentationTestRunn
public int mSoftapIterations = 100;
public int mScanIterations = 100;
public int mReconnectIterations = 100;
- public int mSleepTime = 30 * 1000; // default sleep time is 30 seconds
+ // sleep time before restart wifi, default is set to 2 minutes
+ public int mSleepTime = 2 * 60 * 1000;
public String mReconnectSsid = "securenetdhcp";
public String mReconnectPassword = "androidwifi";
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index adf1883..0580ebc 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -62,6 +62,8 @@ public class ConnectivityManagerTestActivity extends Activity {
public static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
public static final int SHORT_TIMEOUT = 5 * 1000;
public static final long LONG_TIMEOUT = 50 * 1000;
+ // 2 minutes timer between wifi stop and start
+ public static final long WIFI_STOP_START_INTERVAL = 2 * 60 * 1000;
public static final int SUCCESS = 0; // for Wifi tethering state change
public static final int FAILURE = 1;
public static final int INIT = -1;
@@ -247,6 +249,8 @@ public class ConnectivityManagerTestActivity extends Activity {
sleep(SHORT_TIMEOUT);
removeConfiguredNetworksAndDisableWifi();
mWifiRegexs = mCM.getTetherableWifiRegexs();
+ // after wifi is shutdown, wait for 2 minute to enable wifi
+ sleep(WIFI_STOP_START_INTERVAL);
}
public List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java
index d586396..5a4a2d0 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java
@@ -77,10 +77,13 @@ public class NetworkState {
mReason = "no state is recorded.";
return false;
} else if (mStateDepository.size() > 1) {
- Log.v(LOG_TAG, "no broadcast is expected, " +
- "instead broadcast is probably received");
- mReason = "no broadcast is expected, instead broadcast is probably received";
- return false;
+ for (int i = 0; i < mStateDepository.size(); i++) {
+ if (mStateDepository.get(i) != mTransitionTarget) {
+ Log.v(LOG_TAG, "state changed.");
+ mReason = "Unexpected state change";
+ return false;
+ }
+ }
} else if (mStateDepository.get(0) != mTransitionTarget) {
Log.v(LOG_TAG, mTransitionTarget + " is expected, but it is " +
mStateDepository.get(0));
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index d9b770a..b1f4bf1 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -66,7 +66,7 @@ public class ConnectivityManagerMobileTest
// Each test case will start with cellular connection
if (Settings.System.getInt(getInstrumentation().getContext().getContentResolver(),
Settings.System.AIRPLANE_MODE_ON) == 1) {
- Log.v(LOG_TAG, "airplane is not disabled, disable it.");
+ log("airplane is not disabled, disable it.");
cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
}
if (!UtilHelper.isWifiOnly()) {
@@ -84,13 +84,13 @@ public class ConnectivityManagerMobileTest
@Override
public void tearDown() throws Exception {
cmActivity.finish();
- Log.v(LOG_TAG, "tear down ConnectivityManagerTestActivity");
+ log("tear down ConnectivityManagerTestActivity");
wl.release();
cmActivity.removeConfiguredNetworksAndDisableWifi();
// if airplane mode is set, disable it.
if (Settings.System.getInt(getInstrumentation().getContext().getContentResolver(),
Settings.System.AIRPLANE_MODE_ON) == 1) {
- Log.v(LOG_TAG, "disable airplane mode if it is enabled");
+ log("disable airplane mode if it is enabled");
cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
}
super.tearDown();
@@ -104,17 +104,24 @@ public class ConnectivityManagerMobileTest
assertTrue("not connected to cellular network", extraNetInfo.isConnected());
}
+ private void log(String message) {
+ Log.v(LOG_TAG, message);
+ }
+
+ private void sleep(long sleeptime) {
+ try {
+ Thread.sleep(sleeptime);
+ } catch (InterruptedException e) {}
+ }
+
// Test case 1: Test enabling Wifi without associating with any AP, no broadcast on network
// event should be expected.
@LargeTest
public void test3GToWifiNotification() {
// Enable Wi-Fi to avoid initial UNKNOWN state
cmActivity.enableWifi();
- try {
- Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
- } catch (Exception e) {
- Log.v(LOG_TAG, "exception: " + e.toString());
- }
+ sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+
// Wi-Fi is disabled
cmActivity.disableWifi();
@@ -123,11 +130,8 @@ public class ConnectivityManagerMobileTest
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
// Wait for 10 seconds for broadcasts to be sent out
- try {
- Thread.sleep(10 * 1000);
- } catch (Exception e) {
- fail("thread in sleep is interrupted.");
- }
+ sleep(10 * 1000);
+
// As Wifi stays in DISCONNETED, Mobile statys in CONNECTED,
// the connectivity manager will not broadcast any network connectivity event for Wifi
NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
@@ -138,22 +142,18 @@ public class ConnectivityManagerMobileTest
NetworkState.DO_NOTHING, State.DISCONNECTED);
// Eanble Wifi without associating with any AP
cmActivity.enableWifi();
- try {
- Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
- } catch (Exception e) {
- Log.v(LOG_TAG, "exception: " + e.toString());
- }
+ sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
// validate state and broadcast
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
- Log.v(LOG_TAG, "the state for WIFI is changed");
- Log.v(LOG_TAG, "reason: " +
+ log("the state for WIFI is changed");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue("state validation fail", false);
}
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
- Log.v(LOG_TAG, "the state for MOBILE is changed");
- Log.v(LOG_TAG, "reason: " +
+ log("the state for MOBILE is changed");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue("state validation fail", false);
}
@@ -182,7 +182,7 @@ public class ConnectivityManagerMobileTest
assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
ConnectivityManagerTestActivity.LONG_TIMEOUT));
- Log.v(LOG_TAG, "wifi state is enabled");
+ log("wifi state is enabled");
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
ConnectivityManagerTestActivity.LONG_TIMEOUT));
if (!UtilHelper.isWifiOnly()) {
@@ -192,15 +192,15 @@ public class ConnectivityManagerMobileTest
// validate states
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
- Log.v(LOG_TAG, "Wifi state transition validation failed.");
- Log.v(LOG_TAG, "reason: " +
+ log("Wifi state transition validation failed.");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
if (!UtilHelper.isWifiOnly()) {
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
- Log.v(LOG_TAG, "Mobile state transition validation failed.");
- Log.v(LOG_TAG, "reason: " +
+ log("Mobile state transition validation failed.");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
@@ -219,16 +219,11 @@ public class ConnectivityManagerMobileTest
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
ConnectivityManagerTestActivity.LONG_TIMEOUT));
- try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
- } catch (Exception e) {
- Log.v(LOG_TAG, "exception: " + e.toString());
- }
-
+ sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
// Disable Wifi
- Log.v(LOG_TAG, "Disable Wifi");
+ log("Disable Wifi");
if (!cmActivity.disableWifi()) {
- Log.v(LOG_TAG, "disable Wifi failed");
+ log("disable Wifi failed");
return;
}
@@ -254,8 +249,10 @@ public class ConnectivityManagerMobileTest
cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_CONNECTION, State.CONNECTED);
+ // wait for 2 minutes before restart wifi
+ sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL);
// Enable Wifi again
- Log.v(LOG_TAG, "Enable Wifi again");
+ log("Enable Wifi again");
cmActivity.enableWifi();
// Wait for Wifi to be connected and mobile to be disconnected
@@ -268,8 +265,8 @@ public class ConnectivityManagerMobileTest
// validate wifi states
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
- Log.v(LOG_TAG, "Wifi state transition validation failed.");
- Log.v(LOG_TAG, "reason: " +
+ log("Wifi state transition validation failed.");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
@@ -288,11 +285,7 @@ public class ConnectivityManagerMobileTest
ConnectivityManagerTestActivity.LONG_TIMEOUT));
// Wait for a few seconds to avoid the state that both Mobile and Wifi is connected
- try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
- } catch (Exception e) {
- Log.v(LOG_TAG, "exception: " + e.toString());
- }
+ sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
NetworkInfo networkInfo;
if (!UtilHelper.isWifiOnly()) {
@@ -318,15 +311,15 @@ public class ConnectivityManagerMobileTest
// validate states
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
- Log.v(LOG_TAG, "Wifi state transition validation failed.");
- Log.v(LOG_TAG, "reason: " +
+ log("Wifi state transition validation failed.");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
if (!UtilHelper.isWifiOnly()) {
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
- Log.v(LOG_TAG, "Mobile state transition validation failed.");
- Log.v(LOG_TAG, "reason: " +
+ log("Mobile state transition validation failed.");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
@@ -346,19 +339,16 @@ public class ConnectivityManagerMobileTest
assertEquals(State.DISCONNECTED, networkInfo.getState());
// Enable airplane mode
+ log("Enable airplane mode");
cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
- try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
- } catch (Exception e) {
- Log.v(LOG_TAG, "exception: " + e.toString());
- }
+ sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
assertEquals(State.DISCONNECTED, networkInfo.getState());
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
- Log.v(LOG_TAG, "Mobile state transition validation failed.");
- Log.v(LOG_TAG, "reason: " +
+ log("Mobile state transition validation failed.");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
@@ -381,14 +371,14 @@ public class ConnectivityManagerMobileTest
// Validate the state transition
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
- Log.v(LOG_TAG, "Mobile state transition validation failed.");
- Log.v(LOG_TAG, "reason: " +
+ log("Mobile state transition validation failed.");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
- Log.v(LOG_TAG, "Wifi state transition validation failed.");
- Log.v(LOG_TAG, "reason: " +
+ log("Wifi state transition validation failed.");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
@@ -399,6 +389,7 @@ public class ConnectivityManagerMobileTest
public void testDataConnectionOverAMWithWifi() {
assertNotNull("SSID is null", TEST_ACCESS_POINT);
// Eanble airplane mode
+ log("Enable airplane mode");
cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
NetworkInfo networkInfo;
@@ -423,15 +414,15 @@ public class ConnectivityManagerMobileTest
// validate state and broadcast
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
- Log.v(LOG_TAG, "state validate for Wifi failed");
- Log.v(LOG_TAG, "reason: " +
+ log("state validate for Wifi failed");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue("State validation failed", false);
}
if (!UtilHelper.isWifiOnly()) {
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
- Log.v(LOG_TAG, "state validation for Mobile failed");
- Log.v(LOG_TAG, "reason: " +
+ log("state validation for Mobile failed");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue("state validation failed", false);
}
@@ -454,7 +445,7 @@ public class ConnectivityManagerMobileTest
try {
Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
} catch (Exception e) {
- Log.v(LOG_TAG, "exception: " + e.toString());
+ log("exception: " + e.toString());
}
// Enable airplane mode without clearing Wifi
@@ -466,7 +457,7 @@ public class ConnectivityManagerMobileTest
try {
Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
} catch (Exception e) {
- Log.v(LOG_TAG, "exception: " + e.toString());
+ log("exception: " + e.toString());
}
// Prepare for state validation
@@ -487,8 +478,8 @@ public class ConnectivityManagerMobileTest
// validate the state transition
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
- Log.v(LOG_TAG, "Wifi state transition validation failed.");
- Log.v(LOG_TAG, "reason: " +
+ log("Wifi state transition validation failed.");
+ log("reason: " +
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
@@ -511,13 +502,13 @@ public class ConnectivityManagerMobileTest
try {
Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
} catch (Exception e) {
- Log.v(LOG_TAG, "exception: " + e.toString());
+ log("exception: " + e.toString());
}
// Disconnect from the current AP
- Log.v(LOG_TAG, "disconnect from the AP");
+ log("disconnect from the AP");
if (!cmActivity.disconnectAP()) {
- Log.v(LOG_TAG, "failed to disconnect from " + TEST_ACCESS_POINT);
+ log("failed to disconnect from " + TEST_ACCESS_POINT);
}
// Verify the connectivity state for Wifi is DISCONNECTED
@@ -525,7 +516,7 @@ public class ConnectivityManagerMobileTest
ConnectivityManagerTestActivity.LONG_TIMEOUT));
if (!cmActivity.disableWifi()) {
- Log.v(LOG_TAG, "disable Wifi failed");
+ log("disable Wifi failed");
return;
}
assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index 22b1759..d33a445 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -136,7 +136,7 @@ public class WifiConnectionTest
// step 2: verify Wifi state and network state;
assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.CONNECTED, 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ State.CONNECTED, 6 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
// step 3: verify the current connected network is the given SSID
assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
@@ -166,8 +166,9 @@ public class WifiConnectionTest
String ssid = networks.get(i).SSID;
log("-- START Wi-Fi connection test to : " + ssid + " --");
connectToWifi(networks.get(i));
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "interruped while waiting for wifi disabled.");
+ // wait for 2 minutes between wifi stop and start
+ sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL,
+ "interruped while connected to wifi");
log("-- END Wi-Fi connection test to " + ssid + " -- ");
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 7578e67..0b32fde 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -92,6 +92,9 @@ public class WifiStressTest
mPassword = mRunner.mReconnectPassword;
mScanIterations = mRunner.mScanIterations;
mWifiSleepTime = mRunner.mSleepTime;
+ log(String.format("mReconnectIterations(%d), mSsid(%s), mPassword(%s),"
+ + "mScanIterations(%d), mWifiSleepTime(%d)", mReconnectIterations, mSsid,
+ mPassword, mScanIterations, mWifiSleepTime));
mOutputWriter = new BufferedWriter(new FileWriter(new File(
Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
mAct.turnScreenOn();
@@ -248,6 +251,7 @@ public class WifiStressTest
assertTrue("Wi-Fi is connected, but no data connection.", mAct.pingTest(null));
int i;
+ long sum = 0;
for (i = 0; i < mReconnectIterations; i++) {
// 1. Put device into sleep mode
// 2. Wait for the device to sleep for sometime, verify wi-fi is off and mobile is on.
@@ -284,12 +288,18 @@ public class WifiStressTest
// Turn screen on again
mAct.turnScreenOn();
+ // Measure the time for Wi-Fi to get connected
+ long startTime = System.currentTimeMillis();
assertTrue("Wait for Wi-Fi enable timeout after wake up",
mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
ConnectivityManagerTestActivity.SHORT_TIMEOUT));
assertTrue("Wait for Wi-Fi connection timeout after wake up",
mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ 6 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ long connectionTime = System.currentTimeMillis() - startTime;
+ sum += connectionTime;
+ log("average reconnection time is: " + sum/(i+1));
+
assertTrue("Reconnect to Wi-Fi network, but no data connection.", mAct.pingTest(null));
}
if (i == mReconnectIterations) {
diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml
index 58f158c..60b6dc1 100644
--- a/core/tests/bluetoothtests/AndroidManifest.xml
+++ b/core/tests/bluetoothtests/AndroidManifest.xml
@@ -19,6 +19,8 @@
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
index abd7d9a..755e7c4 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
@@ -32,6 +32,8 @@ import android.test.InstrumentationTestCase;
public class BluetoothStressTest extends InstrumentationTestCase {
private static final String TAG = "BluetoothStressTest";
private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt";
+ /** The amount of time to sleep between issuing start/stop SCO in ms. */
+ private static final long SCO_SLEEP_TIME = 2 * 1000;
private BluetoothTestUtils mTestUtils;
@@ -380,11 +382,20 @@ public class BluetoothStressTest extends InstrumentationTestCase {
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("startStopSco iteration " + (i + 1) + " of " + iterations);
mTestUtils.startSco(adapter, device);
+ sleep(SCO_SLEEP_TIME);
mTestUtils.stopSco(adapter, device);
+ sleep(SCO_SLEEP_TIME);
}
mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
mTestUtils.unpair(adapter, device);
mTestUtils.disable(adapter);
}
+
+ private void sleep(long time) {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ }
+ }
}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
index 42e5cd1..4858be8 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
@@ -1425,7 +1425,7 @@ public class BluetoothTestUtils extends Assert {
}
private StartStopScoReceiver getStartStopScoReceiver(int expectedFlags) {
- String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED};
+ String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED};
StartStopScoReceiver receiver = new StartStopScoReceiver(expectedFlags);
addReceiver(receiver, actions);
return receiver;
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
index 3521296..ec12124 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
@@ -26,6 +26,7 @@ import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
+import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityManager;
@@ -54,28 +55,31 @@ public class InterrogationActivityTest
// Timeout before give up wait for the system to process an accessibility setting change.
private static final int TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING = 2000;
+ // Timeout for the accessibility state of an Activity to be fully initialized.
+ private static final int TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS = 100;
+
// Handle to a connection to the AccessibilityManagerService
- private static IAccessibilityServiceConnection sConnection;
+ private static int sConnectionId = View.NO_ID;
// The last received accessibility event
- private static volatile AccessibilityEvent sLastFocusAccessibilityEvent;
+ private volatile AccessibilityEvent mLastAccessibilityEvent;
public InterrogationActivityTest() {
super(InterrogationActivity.class);
}
+ @Override
+ public void setUp() throws Exception {
+ ensureConnection();
+ bringUpActivityWithInitalizedAccessbility();
+ }
+
@LargeTest
public void testFindAccessibilityNodeInfoByViewId() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- // hook into the system first
- IAccessibilityServiceConnection connection = getConnection();
-
- // bring up the activity
- getActivity();
-
AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertNotNull(button);
assertEquals(0, button.getChildCount());
@@ -120,15 +124,9 @@ public class InterrogationActivityTest
public void testFindAccessibilityNodeInfoByViewText() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- // hook into the system first
- IAccessibilityServiceConnection connection = getConnection();
-
- // bring up the activity
- getActivity();
-
// find a view by text
- List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfosByViewTextInActiveWindow(connection, "butto");
+ List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance()
+ .findAccessibilityNodeInfosByViewTextInActiveWindow(sConnectionId, "butto");
assertEquals(9, buttons.size());
} finally {
if (DEBUG) {
@@ -143,15 +141,11 @@ public class InterrogationActivityTest
public void testFindAccessibilityNodeInfoByViewTextContentDescription() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- // hook into the system first
- IAccessibilityServiceConnection connection = getConnection();
-
- // bring up the activity
- getActivity();
+ bringUpActivityWithInitalizedAccessbility();
// find a view by text
- List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfosByViewTextInActiveWindow(connection,
+ List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance()
+ .findAccessibilityNodeInfosByViewTextInActiveWindow(sConnectionId,
"contentDescription");
assertEquals(1, buttons.size());
} finally {
@@ -167,12 +161,6 @@ public class InterrogationActivityTest
public void testTraverseAllViews() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- // hook into the system first
- IAccessibilityServiceConnection connection = getConnection();
-
- // bring up the activity
- getActivity();
-
// make list of expected nodes
List<String> classNameAndTextList = new ArrayList<String>();
classNameAndTextList.add("android.widget.LinearLayout");
@@ -190,7 +178,7 @@ public class InterrogationActivityTest
classNameAndTextList.add("android.widget.ButtonButton9");
AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.root);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.root);
assertNotNull("We must find the existing root.", root);
Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
@@ -227,23 +215,17 @@ public class InterrogationActivityTest
public void testPerformAccessibilityActionFocus() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- // hook into the system first
- IAccessibilityServiceConnection connection = getConnection();
-
- // bring up the activity
- getActivity();
-
// find a view and make sure it is not focused
AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertFalse(button.isFocused());
// focus the view
assertTrue(button.performAction(ACTION_FOCUS));
// find the view again and make sure it is focused
- button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ button = AccessibilityInteractionClient.getInstance()
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertTrue(button.isFocused());
} finally {
if (DEBUG) {
@@ -257,15 +239,9 @@ public class InterrogationActivityTest
public void testPerformAccessibilityActionClearFocus() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- // hook into the system first
- IAccessibilityServiceConnection connection = getConnection();
-
- // bring up the activity
- getActivity();
-
// find a view and make sure it is not focused
AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertFalse(button.isFocused());
// focus the view
@@ -273,7 +249,7 @@ public class InterrogationActivityTest
// find the view again and make sure it is focused
button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertTrue(button.isFocused());
// unfocus the view
@@ -281,7 +257,7 @@ public class InterrogationActivityTest
// find the view again and make sure it is not focused
button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertFalse(button.isFocused());
} finally {
if (DEBUG) {
@@ -296,15 +272,9 @@ public class InterrogationActivityTest
public void testPerformAccessibilityActionSelect() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- // hook into the system first
- IAccessibilityServiceConnection connection = getConnection();
-
- // bring up the activity
- getActivity();
-
// find a view and make sure it is not selected
AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertFalse(button.isSelected());
// select the view
@@ -312,7 +282,7 @@ public class InterrogationActivityTest
// find the view again and make sure it is selected
button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertTrue(button.isSelected());
} finally {
if (DEBUG) {
@@ -326,15 +296,9 @@ public class InterrogationActivityTest
public void testPerformAccessibilityActionClearSelection() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- // hook into the system first
- IAccessibilityServiceConnection connection = getConnection();
-
- // bring up the activity
- getActivity();
-
// find a view and make sure it is not selected
AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertFalse(button.isSelected());
// select the view
@@ -342,15 +306,15 @@ public class InterrogationActivityTest
// find the view again and make sure it is selected
button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertTrue(button.isSelected());
// unselect the view
assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
// find the view again and make sure it is not selected
- button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ button = AccessibilityInteractionClient.getInstance()
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertFalse(button.isSelected());
} finally {
if (DEBUG) {
@@ -365,30 +329,24 @@ public class InterrogationActivityTest
public void testAccessibilityEventGetSource() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- // hook into the system first
- IAccessibilityServiceConnection connection = getConnection();
-
- // bring up the activity
- getActivity();
-
// find a view and make sure it is not focused
AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
assertFalse(button.isSelected());
// focus the view
assertTrue(button.performAction(ACTION_FOCUS));
- synchronized (sConnection) {
+ synchronized (this) {
try {
- sConnection.wait(500);
+ wait(TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS);
} catch (InterruptedException ie) {
/* ignore */
}
}
// check that last event source
- AccessibilityNodeInfo source = sLastFocusAccessibilityEvent.getSource();
+ AccessibilityNodeInfo source = mLastAccessibilityEvent.getSource();
assertNotNull(source);
// bounds
@@ -430,15 +388,9 @@ public class InterrogationActivityTest
public void testObjectContract() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- // hook into the system first
- IAccessibilityServiceConnection connection = getConnection();
-
- // bring up the activity
- getActivity();
-
// find a view and make sure it is not focused
AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5);
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
AccessibilityNodeInfo parent = button.getParent();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -459,24 +411,57 @@ public class InterrogationActivityTest
}
}
- @Override
- protected void scrubClass(Class<?> testCaseClass) {
- /* intentionally do not scrub */
+ private void bringUpActivityWithInitalizedAccessbility() {
+ mLastAccessibilityEvent = null;
+ // bring up the activity
+ getActivity();
+
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ while (true) {
+ if (mLastAccessibilityEvent != null) {
+ final int eventType = mLastAccessibilityEvent.getEventType();
+ if (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+ return;
+ }
+ }
+ final long remainingTimeMillis = TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS
+ - (SystemClock.uptimeMillis() - startTimeMillis);
+ if (remainingTimeMillis <= 0) {
+ return;
+ }
+ synchronized (this) {
+ try {
+ wait(remainingTimeMillis);
+ } catch (InterruptedException e) {
+ /* ignore */
+ }
+ }
+ }
}
- private IAccessibilityServiceConnection getConnection() throws Exception {
- if (sConnection == null) {
+ private void ensureConnection() throws Exception {
+ if (sConnectionId == View.NO_ID) {
IEventListener listener = new IEventListener.Stub() {
- public void setConnection(IAccessibilityServiceConnection connection) {}
+ public void setConnection(IAccessibilityServiceConnection connection,
+ int connectionId) {
+ sConnectionId = connectionId;
+ if (connection != null) {
+ AccessibilityInteractionClient.getInstance().addConnection(connectionId,
+ connection);
+ } else {
+ AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
+ }
+ synchronized (this) {
+ notifyAll();
+ }
+ }
public void onInterrupt() {}
public void onAccessibilityEvent(AccessibilityEvent event) {
- if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
- sLastFocusAccessibilityEvent = AccessibilityEvent.obtain(event);
- }
- synchronized (sConnection) {
- sConnection.notifyAll();
+ mLastAccessibilityEvent = AccessibilityEvent.obtain(event);
+ synchronized (this) {
+ notifyAll();
}
}
};
@@ -485,28 +470,11 @@ public class InterrogationActivityTest
AccessibilityManager.getInstance(getInstrumentation().getContext());
synchronized (this) {
- if (!accessibilityManager.isEnabled()) {
- // Make sure we wake ourselves as the desired state is propagated.
- accessibilityManager.addAccessibilityStateChangeListener(
- new AccessibilityManager.AccessibilityStateChangeListener() {
- public void onAccessibilityStateChanged(boolean enabled) {
- synchronized (this) {
- notifyAll();
- }
- }
- });
- IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
+ IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
- sConnection = manager.registerEventListener(listener);
-
- wait(TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING);
- } else {
- IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
- ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
- sConnection = manager.registerEventListener(listener);
- }
+ manager.registerEventListener(listener);
+ wait(TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING);
}
}
- return sConnection;
}
}
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 10de6ac..fdd9040 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -159,7 +159,7 @@ key 128 MEDIA_STOP
# key 137 "KEY_CUT"
# key 138 "KEY_HELP"
key 139 MENU WAKE_DROPPED
-# key 140 "KEY_CALC"
+key 140 CALCULATOR
# key 141 "KEY_SETUP"
key 142 POWER WAKE
key 143 POWER WAKE
@@ -190,7 +190,7 @@ key 167 MEDIA_RECORD
key 168 MEDIA_REWIND
key 169 CALL
# key 170 "KEY_ISO"
-# key 171 "KEY_CONFIG"
+key 171 MUSIC
key 172 HOME
# key 173 "KEY_REFRESH"
# key 174 "KEY_EXIT"
@@ -232,7 +232,7 @@ key 208 MEDIA_FAST_FORWARD
# key 210 "KEY_PRINT"
# key 211 "KEY_HP"
key 212 CAMERA
-# key 213 "KEY_SOUND"
+key 213 MUSIC
# key 214 "KEY_QUESTION"
key 215 ENVELOPE
# key 216 "KEY_CHAT"
@@ -344,7 +344,7 @@ key 377 TV
# key 394 "KEY_DIRECTORY"
# key 395 "KEY_LIST"
# key 396 "KEY_MEMO"
-# key 397 "KEY_CALENDAR"
+key 397 CALENDAR
# key 398 "KEY_RED"
# key 399 "KEY_GREEN"
# key 400 "KEY_YELLOW"
@@ -364,6 +364,7 @@ key 403 CHANNEL_DOWN
# key 414 "KEY_TEEN"
# key 415 "KEY_TWEN"
+key 429 CONTACTS
# key 448 "KEY_DEL_EOL"
# key 449 "KEY_DEL_EOS"
diff --git a/docs/html/guide/market/billing/billing_admin.jd b/docs/html/guide/market/billing/billing_admin.jd
index cbb4b29..a84eb4e 100755
--- a/docs/html/guide/market/billing/billing_admin.jd
+++ b/docs/html/guide/market/billing/billing_admin.jd
@@ -39,12 +39,12 @@ few administrative tasks, including setting up and maintaining your product list
site, registering test accounts, and handling refunds when necessary.</p>
<p>You must have an Android Market publisher account to register test accounts. And you must have a
-Google Checkout Merchant account to create a product list and issue refunds to your users. If you
+Google Checkout merchant account to create a product list and issue refunds to your users. If you
already have a publisher account on Android Market, you can use your existing account. You do not
need to register for a new account to support in-app billing. If you do not have a publisher
account, you can register as an Android Market developer and set up a publisher account at the
Android Market <a href="http://market.android.com/publish">publisher site</a>. If you do not have a
-Google Checkout Merchant account, you can register for one at the <a
+Google Checkout merchant account, you can register for one at the <a
href="http://checkout.google.com">Google Checkout site</a>.</p>
<h2 id="billing-list-setup">Creating a Product List</h2>
@@ -57,7 +57,7 @@ items that are listed in another application's product list.</p>
<p>You can access an application's product list by clicking the <strong>In-App Products</strong>
link that appears under each of the applications that are listed for your publisher account (see
figure 1). The <strong>In-App Products</strong> link appears only if you have a Google Checkout
-Merchant account and an application's manifest includes the <code>com.android.vending.BILLING</code>
+merchant account and an application's manifest includes the <code>com.android.vending.BILLING</code>
permission.</p>
<img src="{@docRoot}images/billing_product_list_entry.png" height="548" id="figure1" />
@@ -71,20 +71,37 @@ product description, and price (see figure 2). The product list stores only meta
you are selling in your application. It does not store any digital content. You are responsible for
storing and delivering the digital content that you sell in your applications.</p>
-<img src="{@docRoot}images/billing_product_list.png" height="560" id="figure2" />
+<img src="{@docRoot}images/billing_product_list.png" height="658" id="figure2" />
<p class="img-caption">
<strong>Figure 2.</strong> An application's product list.
</p>
-<p>You can create a product list for a published application or a draft application that's been
-uploaded and saved to the Android Market site. However, you must have a Google Checkout Merchant
+<p>You can create a product list for any published application or any draft application that's been
+uploaded and saved to the Android Market site. However, you must have a Google Checkout merchant
account and the application's manifest must include the <code>com.android.vending.BILLING</code>
permission. If an application's manifest does not include this permission, you will be able to edit
existing items in the product list but you will not be able to add new items to the list. For more
-information, see <a href="#billing-permission">Modifying your application's AndroidManifest.xml
-file</a>.</p>
+information about this permission, see
+<a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-permission">Updating Your
+Application's Manifest</a>.</p>
-<p>To create a product list for an application, follow these steps:</p>
+<p>In addition, an application package can have only one product list. If you create a product
+list for an application, and you use the <a
+href="{@docRoot}guide/market/publishing/multiple-apks.html">multiple APK feature</a> to distribute
+more than one APK for that application, the product list applies to all APK versions that are
+associated with the application listing. You cannot create individual product lists for each APK if
+you are using the multiple APK feature.</p>
+
+<p>You can add items to a product list two ways: you can add items one at a time by using the In-app
+Products UI (see figure 3), or you can add a batch of items by importing the items from a
+comma-separated values (CSV) file (see figure 2). Adding items one at a time is useful if your
+application has only a few in-app items or you are adding only a few items to a
+product list for testing purposes. The CSV file method is useful if your application has a large
+number of in-app items.</p>
+
+<h3 id="billing-form-add">Adding items one at a time to a product list</h3>
+
+<p>To add an item to a product list using the In-app Products UI, follow these steps:</p>
<ol>
<li><a href="http://market.android.com/publish">Log in</a> to your publisher account.</li>
@@ -92,7 +109,7 @@ file</a>.</p>
<strong>In-app Products</strong>.</li>
<li>On the In-app Products List page, click <strong>Add in-app product</strong>.</li>
<li>On the Create New In-app Product page (see figure 3), provide details about the item you are
- selling and then click <strong>Save</strong>.</li>
+ selling and then click <strong>Save</strong> or <strong>Publish</strong>.</li>
</ol>
<img src="{@docRoot}images/billing_list_form.png" height="840" id="figure3" />
@@ -109,25 +126,31 @@ file</a>.</p>
(0-9), underlines (_), and dots (.). The product ID "android.test" is reserved, as are all
product IDs that start with "android.test."</p>
<p>In addition, you cannot modify an item's product ID after it is created, and you cannot reuse
- a product ID, even if you delete the item previously using the product ID.</p>
+ a product ID.</p>
</li>
- <li><strong>Purchase type</strong>
- <p>The purchase type can be "managed per user account" or "unmanaged." You can specify an item's
- purchase type only through the publisher site and you can never change an item's purchase type
- once you specify it. For more information, see <a href="#billing_purchase_type">Choosing a
- purchase type</a> later in this document.</p>
+ <li><strong>Purchase Type</strong>
+ <p>The purchase type can be <strong>Managed per user account</strong> or <strong>
+ Unmanaged</strong>. You can never change an item's purchase type after you set it. For more
+ information, see <a href="#billing-purchase-type">Choosing a purchase type</a> later in this
+ document.</p>
</li>
<li><strong>Publishing State</strong>
- <p>An item's publishing state can be "published" or "unpublished." However, to be visible to a
- user during checkout, an item's publishing state must be set to "published" and the item's
- application must be published on Android Market.</p>
+ <p>An item's publishing state can be <strong>Published</strong> or <strong>Unpublished
+ </strong>. To be visible to a user during checkout, an item's publishing state must be set to
+ <strong>Published</strong> and the item's application must be published on Android Market.</p>
<p class="note"><strong>Note:</strong> This is not true for test accounts. An item is visible to
a test account if the application is not published and the item is published. See <a
href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-real">Testing In-app
Billing</a> for more information.</p>
</li>
<li><strong>Language</strong>
- <p>A product list inherits its language from the parent application.</p>
+ <p>The language setting determines which languages are used to display the item title and
+ item description during checkout. A product list inherits its default language from the
+ parent application. You can add more languages by clicking <strong>add language</strong>. You
+ can also choose to have the title and description automatically translated from the default
+ language by selecting the <strong>Fill fields with auto translation</strong> checkbox (see
+ figure 4). If you do not use the auto translation feature, you must provide the translated
+ versions of the title and description.</p>
</li>
<li><strong>Title</strong>
<p>The title is a short descriptor for the item. For example, "Sleeping potion." Titles must be
@@ -141,9 +164,20 @@ file</a>.</p>
visible to users during checkout. Descriptions can be up to 80 characters in length.</p>
</li>
<li><strong>Price</strong>
- <p>Every item must have a price greater than zero; you cannot set a price of "0" (free).</p>
+ <p>You must provide a default price in your home currency. You can also provide prices in other
+ currencies, but you can do this only if a currency's corresponding country is listed as a
+ target country for your application. You can specify target countries on the Edit Application
+ page in the Android Market developer console.</p>
+ <p>To specify prices in other currencies, you can manually enter the price for each
+ currency or you can click <strong>Auto Fill</strong> and let Android Market do a one-time
+ conversion from your home currency to the currencies you are targeting (see figure 4).</p>
</li>
</ul>
+<img src="{@docRoot}images/billing_list_form_2.png" height="1226" id="figure4" />
+<p class="img-caption">
+ <strong>Figure 4.</strong> Specifying additional currencies and additional languages for the
+ item title and description.
+</p>
<p>For more information about product IDs and product lists, see <a
href="http://market.android.com/support/bin/answer.py?answer=1072599">Creating In-App Product
@@ -154,6 +188,197 @@ Pricing</a>.</p>
<p class="note"><strong>Note</strong>: Be sure to plan your product ID namespace. You cannot reuse
or modify product IDs after you save them.</p>
+<h3 id="billing-bulk-add">Adding a batch of items to a product list</h3>
+
+<p>To add a batch of items to a product list using a CSV file, you first need to create your CSV
+file. The data values that you specify in the CSV file represent the same data values you specify
+manually through the In-app Products UI (see <a href="#billing-form-add">Adding items one at a time
+to a product list</a>). The CSV file uses commas (,) and semi-colons (;) to separate data values.
+Commas are used to separate primary data values, and semi-colons are used to separate subvalues. For
+example, the syntax for the CSV file is as follows:</p>
+
+<p>"<em>product_id</em>","<em>publish_state</em>","<em>purchase_type</em>","<em>autotranslate</em>
+","<em>locale</em>; <em>title</em>; <em>description</em>","<em>autofill</em>","<em>country</em>;
+<em>price</em>"
+</p>
+
+<p>Descriptions and usage details are provided below.</p>
+
+<ul>
+ <li><em>product_id</em>
+ <p>This is equivalent to the In-app Product ID setting in the In-app Products UI. If you specify
+ a <em>product_id</em> that already exists in a product list, and you choose to overwrite
+ the product list while importing the CSV file, the data for the existing item is overwritten with
+ the values specified in the CSV file. The overwrite feature does not delete items that are on a
+ product list but not present in the CSV file.</p>
+ </li>
+ <li><em>publish_state</em>
+ <p>This is equivalent to the Publishing State setting in the In-app Products UI. Can be <code>
+ published</code> or <code>unpublished</code>.</p>
+ </li>
+ <li><em>purchase_type</em>
+ <p>This is equivalent to the Purchase Type setting in the In-app Products UI. Can be <code>
+ managed_by_android</code>, which is equivalent to <strong>Managed per user account
+ </strong> in the In-app Products UI, or <code>managed_by_publisher</code>, which is equivalent
+ to <strong>Unmanaged</strong> in the In-app Products UI.</p>
+ </li>
+ <li><em>autotranslate</em>
+ <p>This is equivalent to selecting the <strong>Fill fields with auto translation</strong>
+ checkbox in the In-app Products UI. Can be <code>true</code> or <code>false</code>.</p>
+ </li>
+ <li><em>locale</em>
+ <p>This is equivalent to the Language setting in the In-app Products UI. You must have an entry
+ for the default locale. The default locale must be the first entry in the list of
+ locales, and it must include a <em>title</em> and <em>description</em>. If you want to provide
+ translated versions of the <em>title</em> and <em>description</em> in addition to the default,
+ you must use the following syntax rules:</p>
+ <p>If <em>autotranslate</em> is <code>true</code>, you must specify the default locale,
+ default title, default description, and other locales using the following format:</p>
+ <p>"true,"<em>default_locale</em>; <em>default_locale_title</em>;
+ <em>default_locale_description</em>; <em>locale_2</em>; <em>locale_3</em>, ..."</p>
+ <p>If <em>autotranslate</em> is <code>false</code>, you must specify the default locale,
+ default title, and default description as well as the translated titles and descriptions using
+ the following format:</p>
+ <p>"false,"<em>default_locale</em>; <em>default_locale_title</em>;
+ <em>default_locale_description</em>; <em>locale_2</em>; <em>locale_2_title</em>;
+ <em>local_2_description</em>; <em>locale_3</em>; <em>locale_3_title</em>;
+ <em>locale_3_description</em>; ..."</p>
+ <p>See table 1 for a list of the language codes you can use with the <em>locale</em> field.</p>
+ </li>
+ <li><em>title</em>
+ <p>This is equivalent to the Title setting in the In-app Products UI. If the <em>title</em>
+ contains a semicolon, it must be escaped with a backslash (for example, "\;"). A backslash
+ should also be escaped with a backslash (for example, "\\">.</p>
+ </li>
+ <li><em>description</em>
+ <p>This is equivalent to the Description in the In-app Products UI. If the <em>description</em>
+ contains a semicolon, it must be escaped with a backslash (for example, "\;"). A backslash
+ should also be escaped with a backslash (for example, "\\">.</p>
+ </li>
+ <li><em>autofill</em>
+ <p>This is equivalent to clicking <strong>Auto Fill</strong> in the In-app Products UI. Can be
+ <code>true</code> or <code>false</code>. The syntax for specifying the <em>country</em>
+ and <em>price</em> varies depending on which <em>autofill</em> setting you use.</p>
+ <p>If <em>autofill</em> is set to <code>true</code>, you need to specify only the default
+ price in your home currency and you must use this syntax:</p>
+ <p>"true","<em>default_price_in_home_currency</em>"
+ <p>If <em>autofill</em> is set to <code>false</code>, you need to specify a <em>country</em>
+ and a <em>price</em> for each currency and you must use the following syntax:</p>
+ <p>"false", "<em>home_country</em>; <em>default_price_in_home_currency</em>; <em>country_2</em>;
+ <em>country_2_price</em>; <em>country_3</em>; <em>country_3_price</em>; ..."</p>
+ </li>
+ <li><em>country</em>
+ <p>The country for which you are specifying a price. You can only list countries that your
+ application is targeting. The country codes are two-letter uppercase
+ ISO country codes (such as "US") as defined by
+ <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-2</a>.</p>
+ </li>
+ <li><em>price</em>
+ <p>This is equivalent to the Price in the In-app Products UI. The price must be specified in
+ micro-units. To convert a currency value to micro-units, you multiply the real value by 1,000,000.
+ For example, if you want to sell an in-app item for $1.99 you specify 1990000 in the
+ <em>price</em> field.</p>
+ </li>
+</ul>
+
+<p class="table-caption" id="language-table"><strong>Table 1.</strong> Language codes you can use
+with the <em>locale</em> field.</p>
+
+<table>
+
+<tr>
+<th>Language</th>
+<th>Code</th>
+<th>Language</th>
+<th>Code</th>
+</tr>
+<tr>
+<td>Chinese</td>
+<td>zh_TW</td>
+<td>Italian</td>
+<td>it_IT</td>
+</tr>
+<tr>
+<td>Czech</td>
+<td>cs_CZ</td>
+<td>Japanese</td>
+<td>ja_JP</td>
+</tr>
+<tr>
+<td>Danish</td>
+<td>da_DK</td>
+<td>Korean</td>
+<td>ko_KR</td>
+</tr>
+<tr>
+<td>Dutch</td>
+<td>nl_NL</td>
+<td>Norwegian</td>
+<td>no_NO</td>
+</tr>
+<tr>
+<td>English</td>
+<td>en_US</td>
+<td>Polish</td>
+<td>pl_PL</td>
+</tr>
+<tr>
+<td>French</td>
+<td>fr_FR</td>
+<td>Portuguese</td>
+<td>pt_PT</td>
+</tr>
+<tr>
+<td>Finnish</td>
+<td>fi_FI</td>
+<td>Russian</td>
+<td>ru_RU</td>
+</tr>
+<tr>
+<td>German</td>
+<td>de_DE</td>
+<td>Spanish</td>
+<td>es_ES</td>
+</tr>
+<tr>
+<td>Hebrew</td>
+<td>iw_IL</td>
+<td>Swedish</td>
+<td>sv_SE</td>
+</tr>
+<tr>
+<td>Hindi</td>
+<td>hi_IN</td>
+<td>--</td>
+<td>--</td>
+</tr>
+</table>
+
+<p>To import the items that are specified in your CSV file, do the following:</p>
+
+<ol>
+ <li><a href="http://market.android.com/publish">Log in</a> to your publisher account.</li>
+ <li>In the <strong>All Android Market listings</strong> panel, under the application name, click
+ <strong>In-app Products</strong>.</li>
+ <li>On the In-app Products List page, click <strong>Choose File</strong> and select your CSV
+file.
+ <p>The CSV file must be on your local computer or on a local disk that is connected to your
+ computer.</p>
+ </li>
+ <li>Select the <strong>Overwrite</strong> checkbox if you want to overwrite existing items in
+ your product list.
+ <p>This option overwrites values of existing items only if the value of the <em>product_id</em>
+ in the CSV file matches the In-app Product ID for an existing item in the product list.
+ Overwriting does not delete items that are on a product list but not present in the CSV
+ file.</p>
+ </li>
+ <li>On the In-app Products List page, click <strong>Import from CSV</strong>.</li>
+</ol>
+
+<p>You can also export an existing product list to a CSV file by clicking <strong>Export to CSV
+</strong> on the In-app Product List page. This is useful if you have manually added items to
+a product list and you want to start managing the product list through a CSV file.</p>
+
<h3 id="billing-purchase-type">Choosing a Purchase Type</h3>
<p>An item's purchase type controls how Android Market manages the purchase of the item. There are
@@ -194,7 +419,7 @@ times.</p>
<p>In-app billing does not allow users to send a refund request to Android Market. Refunds for
in-app purchases must be directed to you (the application developer). You can then process the
-refund through your Google Checkout Merchant account. When you do this, Android Market receives a
+refund through your Google Checkout merchant account. When you do this, Android Market receives a
refund notification from Google Checkout, and Android Market sends a refund message to your
application. For more information, see <a
href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling
@@ -236,15 +461,15 @@ accounts yourself and distribute the credentials to your developers or testers.<
<li><a href="http://market.android.com/publish">Log in</a> to your publisher account.</li>
<li>On the upper left part of the page, under your name, click <strong>Edit profile</strong>.</li>
<li>On the Edit Profile page, scroll down to the Licensing &amp; In-app Billing panel (see figure
- 4).</li>
+ 5).</li>
<li>In Test Accounts, add the email addresses for the test accounts you want to register,
separating each account with a comma.</li>
<li>Click <strong>Save</strong> to save your profile changes.</li>
</ol>
-<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure4" />
+<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure5" />
<p class="img-caption">
- <strong>Figure 4.</strong> The Licensing and In-app Billing panel of your account's Edit Profile
+ <strong>Figure 5.</strong> The Licensing and In-app Billing panel of your account's Edit Profile
page lets you register test accounts.
</p>
diff --git a/docs/html/guide/practices/ui_guidelines/widget_design.jd b/docs/html/guide/practices/ui_guidelines/widget_design.jd
index de20e00..f63f3c4 100644
--- a/docs/html/guide/practices/ui_guidelines/widget_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/widget_design.jd
@@ -250,13 +250,15 @@ android.widget.FrameLayout}. Just as your activity layouts must adapt to differe
sizes, widget layouts must adapt to different Home screen grid cell sizes.</p>
<p>Below is an example layout that a music widget showing text information and two buttons can use.
-It builds upon the previous discussion of adding margins depending on OS version.</p>
+It builds upon the previous discussion of adding margins depending on OS version. Note that the
+most robust and resilient way to add margins to the widget is to wrap the widget frame and contents
+in a padded {@link android.widget.FrameLayout}.</p>
<pre>
&lt;FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_margin="@dimen/widget_margin"&gt;
+ android:padding="@dimen/widget_margin"&gt;
&lt;LinearLayout
android:layout_width="match_parent"
@@ -295,16 +297,16 @@ use flexible layouts attributes like so:</p>
<p>When a user adds the widget to their home screen, on an example Android 4.0 device where each
-grid cell is 80dp &times; 100dp in size and 16dp of margins are automatically applied on all sizes,
+grid cell is 80dp &times; 100dp in size and 8dp of margins are automatically applied on all sizes,
the widget will be stretched, like so:</p>
<img src="{@docRoot}images/widget_design/music_example_stretched.png"
- alt="Music widget sitting on an example 80dp x 100dp grid with 16dp of automatic margins
+ alt="Music widget sitting on an example 80dp x 100dp grid with 8dp of automatic margins
added by the system" id="music_example_stretched">
<p class="img-caption"><strong>Figure 7.</strong> Music widget sitting on an example 80dp x 100dp
-grid with 16dp of automatic margins added by the system.</p>
+grid with 8dp of automatic margins added by the system.</p>
<h2 id="templates">Using the App Widget Templates Pack</h2>
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index 61337b7..2cb23c1 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -346,7 +346,7 @@ following layout classes:</p>
&lt;FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- <strong>android:layout_margin="@dimen/widget_margin"&gt;</strong>
+ <strong>android:padding="@dimen/widget_margin"&gt;</strong>
&lt;LinearLayout
android:layout_width="match_parent"
@@ -363,7 +363,7 @@ following layout classes:</p>
<li>Create two dimensions resources, one in <code>res/values/</code> to provide the pre-Android 4.0 custom margins, and one in <code>res/values-v14/</code> to provide no extra padding for Android 4.0 widgets:
<p><strong>res/values/dimens.xml</strong>:<br>
- <pre>&lt;dimen name="widget_margin"&gt;15dp&lt;/dimen&gt;</pre></p>
+ <pre>&lt;dimen name="widget_margin"&gt;8dp&lt;/dimen&gt;</pre></p>
<p><strong>res/values-v14/dimens.xml</strong>:<br>
<pre>&lt;dimen name="widget_margin"&gt;0dp&lt;/dimen&gt;</pre></p>
diff --git a/docs/html/guide/topics/renderscript/index.jd b/docs/html/guide/topics/renderscript/index.jd
index eb77310..148705c 100644
--- a/docs/html/guide/topics/renderscript/index.jd
+++ b/docs/html/guide/topics/renderscript/index.jd
@@ -151,10 +151,9 @@ page.title=RenderScript
defining two-, three-, or four-vectors.</li>
</ul>
- <p>The <a href="{@docRoot}guide/topics/renderscript/rs-api/files.html">RenderScript header files</a>
- and LLVM front-end libraries are located in the <code>include</code> and
- <code>clang-include</code> directories in the
- <code>&lt;sdk_root&gt;/platforms/android-11/renderscript</code> directory of the Android SDK. The
+ <p>The RenderScript header files and LLVM front-end libraries are located in the <code>include/</code> and
+ <code>clang-include/</code> directories in the
+ <code>&lt;sdk_root&gt;/platforms/android-11/renderscript/</code> directory of the Android SDK. The
headers are automatically included for you, except for the RenderScript graphics specific header file, which
you can include as follows:</p>
<pre>
diff --git a/docs/html/images/billing_list_form_2.png b/docs/html/images/billing_list_form_2.png
new file mode 100755
index 0000000..d321a20
--- /dev/null
+++ b/docs/html/images/billing_list_form_2.png
Binary files differ
diff --git a/docs/html/images/billing_product_list.png b/docs/html/images/billing_product_list.png
index 49a7e79..a89f21b 100755
--- a/docs/html/images/billing_product_list.png
+++ b/docs/html/images/billing_product_list.png
Binary files differ
diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd
index 07a0e43..4d0abec 100644
--- a/docs/html/resources/dashboard/opengl.jd
+++ b/docs/html/resources/dashboard/opengl.jd
@@ -57,7 +57,7 @@ ending on the data collection date noted below.</p>
<div class="dashboard-panel">
<img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A9.8,90.2" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A10.1,89.9" />
<table>
<tr>
@@ -66,14 +66,14 @@ src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=
</tr>
<tr>
<td>1.1</th>
-<td>9.8%</td>
+<td>10.1%</td>
</tr>
<tr>
<td>2.0</th>
-<td>90.2%</td>
+<td>89.9%</td>
</tr>
</table>
-<p><em>Data collected during a 7-day period ending on November 3, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on December 1, 2011</em></p>
</div>
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 8041096..72370bb 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@ Android Market within a 14-day period ending on the data collection date noted b
<div class="dashboard-panel">
<img alt="" height="250" width="470"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.9,1.4,10.7,40.7,0.5,43.9,0.1,0.9,0.9&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.8,1.3,9.6,35.3,0.5,50.1,0.1,1.1,1.2&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2&chco=c4df9b,6fad0c" />
<table>
<tr>
@@ -61,21 +61,21 @@ src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.9,1.4,10.7,40
<th>API Level</th>
<th>Distribution</th>
</tr>
-<tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td> <td>3</td><td>0.9%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td> <td>4</td><td>1.4%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td> <td>7</td><td>10.7%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td> <td>8</td><td>40.7%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td> <td>3</td><td>0.8%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td> <td>4</td><td>1.3%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td> <td>7</td><td>9.6%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td> <td>8</td><td>35.3%</td></tr>
<tr><td><a href="{@docRoot}sdk/android-2.3.html">Android 2.3 -<br/>
Android 2.3.2</a></td><td rowspan="2">Gingerbread</td> <td>9</td><td>0.5%</td></tr>
<tr><td><a href="{@docRoot}sdk/android-2.3.3.html">Android 2.3.3 -<br/>
- Android 2.3.7</a></td><!-- Gingerbread --> <td>10</td><td>43.9%</td></tr>
+ Android 2.3.7</a></td><!-- Gingerbread --> <td>10</td><td>50.1%</td></tr>
<tr><td><a href="{@docRoot}sdk/android-3.0.html">Android 3.0</a></td>
<td rowspan="3">Honeycomb</td> <td>11</td><td>0.1%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>0.9%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>0.9%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>1.1%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>1.2%</td></tr>
</table>
-<p><em>Data collected during a 14-day period ending on November 3, 2011</em></p>
+<p><em>Data collected during a 14-day period ending on December 1, 2011</em></p>
<!--
<p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
-->
@@ -104,9 +104,9 @@ Android Market within a 14-day period ending on the date indicated on the x-axis
<div class="dashboard-panel">
<img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.6,99.5,99.4,99.3,99.2,99.0,98.8,98.7,98.5,98.5,98.2,98.1,98.0|97.3,97.5,97.5,97.5,97.7,97.6,97.5,97.5,97.5,97.5,97.1,97.1,97.1|94.3,94.8,95.0,95.2,95.5,95.5,95.5,95.6,95.7,95.8,95.6,95.9,95.7|69.8,71.5,73.9,75.4,77.6,79.0,80.2,81.1,82.4,83.3,83.8,84.9,85.0|4.0,6.1,9.5,13.6,17.8,20.6,24.3,27.5,31.2,34.7,38.3,41.3,44.0|3.0,5.1,8.4,12.6,16.8,20.0,23.7,26.9,30.6,34.1,37.8,40.8,43.5&chm=b,c3df9b,0,1,0|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|tAndroid 2.3.3,131d02,5,3,15,,t::-5|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A|06/01|06/15|07/01|07/15|08/01|08/15|09/01|09/15|10/01|10/15|11/01|11/15|12/01|1%3A|2011||||||||||||2011|2%3A|0%25|25%25|50%25|75%25|100%25|3%3A|0%25|25%25|50%25|75%25|100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.4,99.3,99.2,99.0,98.8,98.7,98.5,98.5,98.2,98.1,98.0,99.9,99.9|97.5,97.5,97.7,97.6,97.5,97.5,97.5,97.5,97.1,97.1,97.0,99.1,99.1|95.0,95.2,95.5,95.5,95.5,95.6,95.7,95.8,95.6,95.9,95.7,97.7,97.8|73.9,75.4,77.6,79.0,80.2,81.1,82.4,83.3,83.8,84.9,85.1,87.5,88.2|9.5,13.6,17.8,20.6,24.3,27.5,31.2,34.7,38.3,41.3,44.0,48.9,52.9|8.4,12.6,16.8,20.0,23.7,26.9,30.6,34.1,37.8,40.8,43.5,48.4,52.4|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,2.3|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.2&chm=b,c3df9b,0,1,0|b,b8dc82,1,2,0|tAndroid%202.1,608920,2,0,15,,t::-5|b,addb67,2,3,0|tAndroid%202.2,517617,3,0,15,,t::-5|b,a3db4b,3,4,0|b,98dc2e,4,5,0|tAndroid%202.3.3,334d0a,5,1,15,,t::-5|b,8cd41b,5,6,0|b,7ec113,6,7,0|B,6fad0c,7,8,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.1|Android%203.2&chco=add274,a2d15a,97d13e,8bcb28,7dba1e,6ea715,5f920e,507d08" />
-<p><em>Last historical dataset collected during a 14-day period ending on November 3, 2011</em></p>
+<p><em>Last historical dataset collected during a 14-day period ending on December 1, 2011</em></p>
</div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index ec3034d..79d59d9 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -60,7 +60,7 @@ ending on the data collection date noted below.</p>
<div class="dashboard-panel">
<img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A2.9,0.1,3.1,70.8,1.0,17.7,3.0,1.3" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A3.1,0.1,3.1,71.0,1.0,17.5,2.9,1.3" />
<table>
<tr>
@@ -73,13 +73,13 @@ src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=
<tr><th scope="row">small</th>
<td>1.3%</td> <!-- small/ldpi -->
<td></td> <!-- small/mdpi -->
-<td>3.0%</td> <!-- small/hdpi -->
+<td>2.9%</td> <!-- small/hdpi -->
<td></td> <!-- small/xhdpi -->
</tr>
<tr><th scope="row">normal</th>
<td>1.0%</td> <!-- normal/ldpi -->
-<td>17.7%</td> <!-- normal/mdpi -->
-<td>70.8%</td> <!-- normal/hdpi -->
+<td>17.5%</td> <!-- normal/mdpi -->
+<td>71%</td> <!-- normal/hdpi -->
<td></td> <!-- normal/xhdpi -->
</tr>
<tr><th scope="row">large</th>
@@ -90,12 +90,12 @@ src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=
</tr>
<tr><th scope="row">xlarge</th>
<td></td> <!-- xlarge/ldpi -->
-<td>2.9%</td> <!-- xlarge/mdpi -->
+<td>3.1%</td> <!-- xlarge/mdpi -->
<td></td> <!-- xlarge/hdpi -->
<td></td> <!-- xlarge/xhdpi -->
</tr>
</table>
-<p><em>Data collected during a 7-day period ending on November 3, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on December 1, 2011</em></p>
</div>
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 15c2bab..a8c7672 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -60,10 +60,16 @@ public:
virtual void onFrameAvailable() = 0;
};
- // tex indicates the name OpenGL texture to which images are to be streamed.
- // This texture name cannot be changed once the SurfaceTexture is created.
+ // SurfaceTexture constructs a new SurfaceTexture object. tex indicates the
+ // name of the OpenGL ES texture to which images are to be streamed. This
+ // texture name cannot be changed once the SurfaceTexture is created.
+ // allowSynchronousMode specifies whether or not synchronous mode can be
+ // enabled. texTarget specifies the OpenGL ES texture target to which the
+ // texture will be bound in updateTexImage. useFenceSync specifies whether
+ // fences should be used to synchronize access to buffers if that behavior
+ // is enabled at compile-time.
SurfaceTexture(GLuint tex, bool allowSynchronousMode = true,
- GLenum texTarget = GL_TEXTURE_EXTERNAL_OES);
+ GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true);
virtual ~SurfaceTexture();
@@ -276,7 +282,8 @@ private:
mTransform(0),
mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mTimestamp(0),
- mFrameNumber(0) {
+ mFrameNumber(0),
+ mFence(EGL_NO_SYNC_KHR) {
mCrop.makeInvalid();
}
@@ -349,6 +356,11 @@ private:
// mFrameNumber is the number of the queued frame for this slot.
uint64_t mFrameNumber;
+ // mFence is the EGL sync object that must signal before the buffer
+ // associated with this buffer slot may be dequeued. It is initialized
+ // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
+ // on a compile-time option) set to a new sync object in updateTexImage.
+ EGLSyncKHR mFence;
};
// mSlots is the array of buffer slots that must be mirrored on the client
@@ -472,6 +484,12 @@ private:
// It is set by the setName method.
String8 mName;
+ // mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync
+ // extension should be used to prevent buffers from being dequeued before
+ // it's safe for them to be written. It gets set at construction time and
+ // never changes.
+ const bool mUseFenceSync;
+
// mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
index cc63356..19646b0 100644
--- a/include/media/IStreamSource.h
+++ b/include/media/IStreamSource.h
@@ -52,15 +52,20 @@ struct IStreamListener : public IInterface {
static const char *const kKeyResumeAtPTS;
// When signalling a discontinuity you can optionally
- // signal that this is a "hard" discontinuity, i.e. the format
- // or configuration of subsequent stream data differs from that
- // currently active. To do so, include a non-zero int32_t value
- // under the key "kKeyFormatChange" when issuing the DISCONTINUITY
+ // specify the type(s) of discontinuity, i.e. if the
+ // audio format has changed, the video format has changed,
+ // time has jumped or any combination thereof.
+ // To do so, include a non-zero int32_t value
+ // under the key "kKeyDiscontinuityMask" when issuing the DISCONTINUITY
// command.
- // The new logical stream must start with proper codec initialization
+ // If there is a change in audio/video format, The new logical stream
+ // must start with proper codec initialization
// information for playback to continue, i.e. SPS and PPS in the case
// of AVC video etc.
- static const char *const kKeyFormatChange;
+ // If this key is not present, only a time discontinuity is assumed.
+ // The value should be a bitmask of values from
+ // ATSParser::DiscontinuityType.
+ static const char *const kKeyDiscontinuityMask;
virtual void issueCommand(
Command cmd, bool synchronous, const sp<AMessage> &msg = NULL) = 0;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 5822877..3963d9c 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -166,6 +166,8 @@ private:
bool allYourBuffersAreBelongToUs();
+ size_t countBuffersOwnedByComponent(OMX_U32 portIndex) const;
+
void deferMessage(const sp<AMessage> &msg);
void processDeferredMessages();
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index b9deafc..6ab01f4 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -63,6 +63,7 @@ public:
USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER,
USAGE_HW_2D = GRALLOC_USAGE_HW_2D,
USAGE_HW_COMPOSER = GRALLOC_USAGE_HW_COMPOSER,
+ USAGE_HW_VIDEO_ENCODER = GRALLOC_USAGE_HW_VIDEO_ENCODER,
USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK
};
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index 2efe8ca..c5bd0c5 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -231,6 +231,10 @@ static const KeycodeLabel KEYCODES[] = {
{ "LANGUAGE_SWITCH", 204 },
{ "MANNER_MODE", 205 },
{ "3D_MODE", 206 },
+ { "CONTACTS", 207 },
+ { "CALENDAR", 208 },
+ { "MUSIC", 209 },
+ { "CALCULATOR", 210 },
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index beb23f6..fcd287c 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -36,6 +36,12 @@
#include <utils/Log.h>
#include <utils/String8.h>
+// This compile option causes SurfaceTexture to return the buffer that is currently
+// attached to the GL texture from dequeueBuffer when no other buffers are
+// available. It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
+// implicit cross-process synchronization to prevent the buffer from being
+// written to before the buffer has (a) been detached from the GL texture and
+// (b) all GL reads from the buffer have completed.
#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER true
#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
@@ -43,6 +49,16 @@
#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER false
#endif
+// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
+// to synchronize access to the buffers. It will cause dequeueBuffer to stall,
+// waiting for the GL reads for the buffer being dequeued to complete before
+// allowing the buffer to be dequeued.
+#ifdef USE_FENCE_SYNC
+#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
+#error "USE_FENCE_SYNC and ALLOW_DEQUEUE_CURRENT_BUFFER are incompatible"
+#endif
+#endif
+
// Macros for including the SurfaceTexture name in log messages
#define ST_LOGV(x, ...) LOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
#define ST_LOGD(x, ...) LOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
@@ -99,7 +115,7 @@ static int32_t createProcessUniqueId() {
}
SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
- GLenum texTarget) :
+ GLenum texTarget, bool useFenceSync) :
mDefaultWidth(1),
mDefaultHeight(1),
mPixelFormat(PIXEL_FORMAT_RGBA_8888),
@@ -116,6 +132,11 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
mAllowSynchronousMode(allowSynchronousMode),
mConnectedApi(NO_CONNECTED_API),
mAbandoned(false),
+#ifdef USE_FENCE_SYNC
+ mUseFenceSync(useFenceSync),
+#else
+ mUseFenceSync(false),
+#endif
mTexTarget(texTarget),
mFrameCounter(0) {
// Choose a name using the PID and a process-unique ID.
@@ -261,195 +282,225 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
return BAD_VALUE;
}
- Mutex::Autolock lock(mMutex);
-
status_t returnFlags(OK);
+ EGLDisplay dpy = EGL_NO_DISPLAY;
+ EGLSyncKHR fence = EGL_NO_SYNC_KHR;
- int found = -1;
- int foundSync = -1;
- int dequeuedCount = 0;
- bool tryAgain = true;
- while (tryAgain) {
- if (mAbandoned) {
- ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
-
- // We need to wait for the FIFO to drain if the number of buffer
- // needs to change.
- //
- // The condition "number of buffers needs to change" is true if
- // - the client doesn't care about how many buffers there are
- // - AND the actual number of buffer is different from what was
- // set in the last setBufferCountServer()
- // - OR -
- // setBufferCountServer() was set to a value incompatible with
- // the synchronization mode (for instance because the sync mode
- // changed since)
- //
- // As long as this condition is true AND the FIFO is not empty, we
- // wait on mDequeueCondition.
-
- const int minBufferCountNeeded = mSynchronousMode ?
- MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
-
- const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
- ((mServerBufferCount != mBufferCount) ||
- (mServerBufferCount < minBufferCountNeeded));
-
- if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
- // wait for the FIFO to drain
- mDequeueCondition.wait(mMutex);
- // NOTE: we continue here because we need to reevaluate our
- // whole state (eg: we could be abandoned or disconnected)
- continue;
- }
+ { // Scope for the lock
+ Mutex::Autolock lock(mMutex);
- if (numberOfBuffersNeedsToChange) {
- // here we're guaranteed that mQueue is empty
- freeAllBuffersLocked();
- mBufferCount = mServerBufferCount;
- if (mBufferCount < minBufferCountNeeded)
- mBufferCount = minBufferCountNeeded;
- mCurrentTexture = INVALID_BUFFER_SLOT;
- returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
- }
+ int found = -1;
+ int foundSync = -1;
+ int dequeuedCount = 0;
+ bool tryAgain = true;
+ while (tryAgain) {
+ if (mAbandoned) {
+ ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
- // look for a free buffer to give to the client
- found = INVALID_BUFFER_SLOT;
- foundSync = INVALID_BUFFER_SLOT;
- dequeuedCount = 0;
- for (int i = 0; i < mBufferCount; i++) {
- const int state = mSlots[i].mBufferState;
- if (state == BufferSlot::DEQUEUED) {
- dequeuedCount++;
+ // We need to wait for the FIFO to drain if the number of buffer
+ // needs to change.
+ //
+ // The condition "number of buffers needs to change" is true if
+ // - the client doesn't care about how many buffers there are
+ // - AND the actual number of buffer is different from what was
+ // set in the last setBufferCountServer()
+ // - OR -
+ // setBufferCountServer() was set to a value incompatible with
+ // the synchronization mode (for instance because the sync mode
+ // changed since)
+ //
+ // As long as this condition is true AND the FIFO is not empty, we
+ // wait on mDequeueCondition.
+
+ const int minBufferCountNeeded = mSynchronousMode ?
+ MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+
+ const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
+ ((mServerBufferCount != mBufferCount) ||
+ (mServerBufferCount < minBufferCountNeeded));
+
+ if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
+ // wait for the FIFO to drain
+ mDequeueCondition.wait(mMutex);
+ // NOTE: we continue here because we need to reevaluate our
+ // whole state (eg: we could be abandoned or disconnected)
+ continue;
}
- // if buffer is FREE it CANNOT be current
- LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
- "dequeueBuffer: buffer %d is both FREE and current!", i);
+ if (numberOfBuffersNeedsToChange) {
+ // here we're guaranteed that mQueue is empty
+ freeAllBuffersLocked();
+ mBufferCount = mServerBufferCount;
+ if (mBufferCount < minBufferCountNeeded)
+ mBufferCount = minBufferCountNeeded;
+ mCurrentTexture = INVALID_BUFFER_SLOT;
+ returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+ }
- if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
- if (state == BufferSlot::FREE || i == mCurrentTexture) {
- foundSync = i;
- if (i != mCurrentTexture) {
- found = i;
- break;
- }
+ // look for a free buffer to give to the client
+ found = INVALID_BUFFER_SLOT;
+ foundSync = INVALID_BUFFER_SLOT;
+ dequeuedCount = 0;
+ for (int i = 0; i < mBufferCount; i++) {
+ const int state = mSlots[i].mBufferState;
+ if (state == BufferSlot::DEQUEUED) {
+ dequeuedCount++;
}
- } else {
- if (state == BufferSlot::FREE) {
- /** For Asynchronous mode, we need to return the oldest of free buffers
- * There is only one instance when the Framecounter overflows, this logic
- * might return the earlier buffer to client. Which is a negligible impact
- **/
- if (found < 0 || mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
+
+ // if buffer is FREE it CANNOT be current
+ LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
+ "dequeueBuffer: buffer %d is both FREE and current!",
+ i);
+
+ if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
+ if (state == BufferSlot::FREE || i == mCurrentTexture) {
foundSync = i;
- found = i;
+ if (i != mCurrentTexture) {
+ found = i;
+ break;
+ }
+ }
+ } else {
+ if (state == BufferSlot::FREE) {
+ /* We return the oldest of the free buffers to avoid
+ * stalling the producer if possible. This is because
+ * the consumer may still have pending reads of the
+ * buffers in flight.
+ */
+ bool isOlder = mSlots[i].mFrameNumber <
+ mSlots[found].mFrameNumber;
+ if (found < 0 || isOlder) {
+ foundSync = i;
+ found = i;
+ }
}
}
}
- }
- // clients are not allowed to dequeue more than one buffer
- // if they didn't set a buffer count.
- if (!mClientBufferCount && dequeuedCount) {
- ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
- "setting the buffer count");
- return -EINVAL;
- }
+ // clients are not allowed to dequeue more than one buffer
+ // if they didn't set a buffer count.
+ if (!mClientBufferCount && dequeuedCount) {
+ ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
+ "setting the buffer count");
+ return -EINVAL;
+ }
+
+ // See whether a buffer has been queued since the last
+ // setBufferCount so we know whether to perform the
+ // MIN_UNDEQUEUED_BUFFERS check below.
+ bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
+ if (bufferHasBeenQueued) {
+ // make sure the client is not trying to dequeue more buffers
+ // than allowed.
+ const int avail = mBufferCount - (dequeuedCount+1);
+ if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
+ ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
+ "(dequeued=%d)",
+ MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
+ dequeuedCount);
+ return -EBUSY;
+ }
+ }
- // See whether a buffer has been queued since the last setBufferCount so
- // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below.
- bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
- if (bufferHasBeenQueued) {
- // make sure the client is not trying to dequeue more buffers
- // than allowed.
- const int avail = mBufferCount - (dequeuedCount+1);
- if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
- ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
- "(dequeued=%d)",
- MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
- dequeuedCount);
- return -EBUSY;
+ // we're in synchronous mode and didn't find a buffer, we need to
+ // wait for some buffers to be consumed
+ tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
+ if (tryAgain) {
+ mDequeueCondition.wait(mMutex);
}
}
- // we're in synchronous mode and didn't find a buffer, we need to wait
- // for some buffers to be consumed
- tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
- if (tryAgain) {
- mDequeueCondition.wait(mMutex);
+ if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
+ // foundSync guaranteed to be != INVALID_BUFFER_SLOT
+ found = foundSync;
}
- }
- if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
- // foundSync guaranteed to be != INVALID_BUFFER_SLOT
- found = foundSync;
- }
+ if (found == INVALID_BUFFER_SLOT) {
+ // This should not happen.
+ ST_LOGE("dequeueBuffer: no available buffer slots");
+ return -EBUSY;
+ }
- if (found == INVALID_BUFFER_SLOT) {
- // This should not happen.
- ST_LOGE("dequeueBuffer: no available buffer slots");
- return -EBUSY;
- }
+ const int buf = found;
+ *outBuf = found;
- const int buf = found;
- *outBuf = found;
+ const bool useDefaultSize = !w && !h;
+ if (useDefaultSize) {
+ // use the default size
+ w = mDefaultWidth;
+ h = mDefaultHeight;
+ }
- const bool useDefaultSize = !w && !h;
- if (useDefaultSize) {
- // use the default size
- w = mDefaultWidth;
- h = mDefaultHeight;
- }
+ const bool updateFormat = (format != 0);
+ if (!updateFormat) {
+ // keep the current (or default) format
+ format = mPixelFormat;
+ }
+
+ // buffer is now in DEQUEUED (but can also be current at the same time,
+ // if we're in synchronous mode)
+ mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
+
+ const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+ if ((buffer == NULL) ||
+ (uint32_t(buffer->width) != w) ||
+ (uint32_t(buffer->height) != h) ||
+ (uint32_t(buffer->format) != format) ||
+ ((uint32_t(buffer->usage) & usage) != usage))
+ {
+ usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+ status_t error;
+ sp<GraphicBuffer> graphicBuffer(
+ mGraphicBufferAlloc->createGraphicBuffer(
+ w, h, format, usage, &error));
+ if (graphicBuffer == 0) {
+ ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
+ "failed");
+ return error;
+ }
+ if (updateFormat) {
+ mPixelFormat = format;
+ }
+ mSlots[buf].mGraphicBuffer = graphicBuffer;
+ mSlots[buf].mRequestBufferCalled = false;
+ mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mSlots[buf].mEglDisplay,
+ mSlots[buf].mEglImage);
+ mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
+ mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+ }
+ if (mCurrentTexture == buf) {
+ // The current texture no longer references the buffer in this slot
+ // since we just allocated a new buffer.
+ mCurrentTexture = INVALID_BUFFER_SLOT;
+ }
+ returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
+ }
- const bool updateFormat = (format != 0);
- if (!updateFormat) {
- // keep the current (or default) format
- format = mPixelFormat;
+ dpy = mSlots[buf].mEglDisplay;
+ fence = mSlots[buf].mFence;
+ mSlots[buf].mFence = EGL_NO_SYNC_KHR;
}
- // buffer is now in DEQUEUED (but can also be current at the same time,
- // if we're in synchronous mode)
- mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
-
- const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
- if ((buffer == NULL) ||
- (uint32_t(buffer->width) != w) ||
- (uint32_t(buffer->height) != h) ||
- (uint32_t(buffer->format) != format) ||
- ((uint32_t(buffer->usage) & usage) != usage))
- {
- usage |= GraphicBuffer::USAGE_HW_TEXTURE;
- status_t error;
- sp<GraphicBuffer> graphicBuffer(
- mGraphicBufferAlloc->createGraphicBuffer(
- w, h, format, usage, &error));
- if (graphicBuffer == 0) {
- ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
- "failed");
- return error;
- }
- if (updateFormat) {
- mPixelFormat = format;
+ if (fence != EGL_NO_SYNC_KHR) {
+ EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+ // If something goes wrong, log the error, but return the buffer without
+ // synchronizing access to it. It's too late at this point to abort the
+ // dequeue operation.
+ if (result == EGL_FALSE) {
+ LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
+ } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ LOGE("dequeueBuffer: timeout waiting for fence");
}
- mSlots[buf].mGraphicBuffer = graphicBuffer;
- mSlots[buf].mRequestBufferCalled = false;
- if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
- mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
- mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
- }
- if (mCurrentTexture == buf) {
- // The current texture no longer references the buffer in this slot
- // since we just allocated a new buffer.
- mCurrentTexture = INVALID_BUFFER_SLOT;
- }
- returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
+ eglDestroySyncKHR(dpy, fence);
}
+
ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", buf,
mSlots[buf].mGraphicBuffer->handle, returnFlags);
+
return returnFlags;
}
@@ -712,8 +763,8 @@ status_t SurfaceTexture::updateTexImage() {
// Update the GL texture object.
EGLImageKHR image = mSlots[buf].mEglImage;
+ EGLDisplay dpy = eglGetCurrentDisplay();
if (image == EGL_NO_IMAGE_KHR) {
- EGLDisplay dpy = eglGetCurrentDisplay();
if (mSlots[buf].mGraphicBuffer == 0) {
ST_LOGE("buffer at slot %d is null", buf);
return BAD_VALUE;
@@ -746,16 +797,32 @@ status_t SurfaceTexture::updateTexImage() {
return -EINVAL;
}
- ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
- mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, buf,
- mSlots[buf].mGraphicBuffer->handle);
+ if (mCurrentTexture != INVALID_BUFFER_SLOT) {
+ if (mUseFenceSync) {
+ EGLSyncKHR fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR,
+ NULL);
+ if (fence == EGL_NO_SYNC_KHR) {
+ LOGE("updateTexImage: error creating fence: %#x",
+ eglGetError());
+ return -EINVAL;
+ }
+ glFlush();
+ mSlots[mCurrentTexture].mFence = fence;
+ }
+ }
+
+ ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
+ mCurrentTexture,
+ mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
+ buf, mSlots[buf].mGraphicBuffer->handle);
if (mCurrentTexture != INVALID_BUFFER_SLOT) {
// The current buffer becomes FREE if it was still in the queued
// state. If it has already been given to the client
// (synchronous mode), then it stays in DEQUEUED state.
- if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED)
+ if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) {
mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE;
+ }
}
// Update the SurfaceTexture state.
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 6d1b951..c313904 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -536,6 +536,20 @@ void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
}
}
+void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
+ uint8_t g, uint8_t b, uint8_t a) {
+ const size_t PIXEL_SIZE = 4;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < h; x++) {
+ off_t offset = (y * stride + x) * PIXEL_SIZE;
+ buf[offset + 0] = r;
+ buf[offset + 1] = g;
+ buf[offset + 2] = b;
+ buf[offset + 3] = a;
+ }
+ }
+}
+
TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
const int texWidth = 64;
const int texHeight = 66;
@@ -1616,4 +1630,101 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
}
}
+class SurfaceTextureFBOTest : public SurfaceTextureGLTest {
+protected:
+
+ virtual void SetUp() {
+ SurfaceTextureGLTest::SetUp();
+
+ glGenFramebuffers(1, &mFbo);
+ ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+
+ glGenTextures(1, &mFboTex);
+ glBindTexture(GL_TEXTURE_2D, mFboTex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(),
+ getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+
+ glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, mFboTex, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+ }
+
+ virtual void TearDown() {
+ SurfaceTextureGLTest::TearDown();
+
+ glDeleteTextures(1, &mFboTex);
+ glDeleteFramebuffers(1, &mFbo);
+ }
+
+ GLuint mFbo;
+ GLuint mFboTex;
+};
+
+// This test is intended to verify that proper synchronization is done when
+// rendering into an FBO.
+TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
+ const int texWidth = 64;
+ const int texHeight = 64;
+
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+ texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
+ ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+ android_native_buffer_t* anb;
+ ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_TRUE(anb != NULL);
+
+ sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+ ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
+
+ // Fill the buffer with green
+ uint8_t* img = NULL;
+ buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
+ 0, 255);
+ buf->unlock();
+ ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+
+ glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+ drawTexture();
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ for (int i = 0; i < 4; i++) {
+ SCOPED_TRACE(String8::format("frame %d", i).string());
+
+ ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_TRUE(anb != NULL);
+
+ buf = new GraphicBuffer(anb, false);
+ ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
+ buf->getNativeBuffer()));
+
+ // Fill the buffer with red
+ ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
+ (void**)(&img)));
+ fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 255, 0,
+ 0, 255);
+ ASSERT_EQ(NO_ERROR, buf->unlock());
+ ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
+ buf->getNativeBuffer()));
+
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+
+ drawTexture();
+
+ EXPECT_TRUE(checkPixel( 24, 39, 255, 0, 0, 255));
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+
+ EXPECT_TRUE(checkPixel( 24, 39, 0, 255, 0, 255));
+}
+
} // namespace android
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index a077cbc..158f785 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -163,7 +163,6 @@ void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len
render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
0, 0, NULL);
}
-
}
void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
@@ -615,7 +614,8 @@ void FontRenderer::issueDrawCommand() {
void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2,
float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3,
float x4, float y4, float z4, float u4, float v4) {
- if (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom) {
+ if (mClip &&
+ (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
return;
}
@@ -723,11 +723,16 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
return image;
}
+ mClip = NULL;
+ mBounds = NULL;
+
Rect bounds;
mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds);
+
uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight];
+
for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) {
dataBuffer[i] = 0;
}
@@ -765,8 +770,11 @@ bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text
mDrawn = false;
mBounds = bounds;
mClip = clip;
+
mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y);
+
mBounds = NULL;
+ mClip = NULL;
if (mCurrentQuadIndex != 0) {
issueDrawCommand();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 7561a47..4d22646 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -201,14 +201,16 @@ void OpenGLRenderer::interrupt() {
}
void OpenGLRenderer::resume() {
- glViewport(0, 0, mSnapshot->viewport.getWidth(), mSnapshot->viewport.getHeight());
+ sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
+
+ glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
glEnable(GL_SCISSOR_TEST);
dirtyClip();
glDisable(GL_DITHER);
- glBindFramebuffer(GL_FRAMEBUFFER, mSnapshot->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
mCaches.blend = true;
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 2e7f213..cd7b3a7 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -21,6 +21,7 @@
#ifndef ANDROID_RS_SERIALIZE
#include <bcinfo/BitcodeTranslator.h>
+#include <bcinfo/BitcodeWrapper.h>
#endif
using namespace android;
@@ -196,7 +197,24 @@ bool ScriptC::runCompiler(Context *rsc,
//LOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen);
#ifndef ANDROID_RS_SERIALIZE
- uint32_t sdkVersion = rsc->getTargetSdkVersion();
+ uint32_t sdkVersion = 0;
+ bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeLen);
+ if (!bcWrapper.unwrap()) {
+ LOGE("Bitcode is not in proper container format (raw or wrapper)");
+ return false;
+ }
+
+ rsAssert(bcWrapper.getHeaderVersion() == 0);
+ if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
+ sdkVersion = bcWrapper.getTargetAPI();
+ }
+
+ if (sdkVersion == 0) {
+ // This signals that we didn't have a wrapper containing information
+ // about the bitcode.
+ sdkVersion = rsc->getTargetSdkVersion();
+ }
+
if (BT) {
delete BT;
}
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index b311f35..078be94 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -30,7 +30,7 @@ namespace android {
const char *const IStreamListener::kKeyResumeAtPTS = "resume-at-PTS";
// static
-const char *const IStreamListener::kKeyFormatChange = "format-change";
+const char *const IStreamListener::kKeyDiscontinuityMask = "discontinuity-mask";
enum {
// IStreamSource
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 2a5c0a6..93ab704 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -54,6 +54,7 @@ NuPlayer::NuPlayer()
mVideoEOS(false),
mScanSourcesPending(false),
mScanSourcesGeneration(0),
+ mTimeDiscontinuityPending(false),
mFlushingAudio(NONE),
mFlushingVideo(NONE),
mResetInProgress(false),
@@ -462,11 +463,24 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
{
LOGV("kWhatReset");
+ if (mRenderer != NULL) {
+ // There's an edge case where the renderer owns all output
+ // buffers and is paused, therefore the decoder will not read
+ // more input data and will never encounter the matching
+ // discontinuity. To avoid this, we resume the renderer.
+
+ if (mFlushingAudio == AWAITING_DISCONTINUITY
+ || mFlushingVideo == AWAITING_DISCONTINUITY) {
+ mRenderer->resume();
+ }
+ }
+
if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
// We're currently flushing, postpone the reset until that's
// completed.
- LOGV("postponing reset");
+ LOGV("postponing reset mFlushingAudio=%d, mFlushingVideo=%d",
+ mFlushingAudio, mFlushingVideo);
mResetPostponed = true;
break;
@@ -477,6 +491,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ mTimeDiscontinuityPending = true;
+
if (mAudioDecoder != NULL) {
flushDecoder(true /* audio */, true /* needShutdown */);
}
@@ -540,7 +556,10 @@ void NuPlayer::finishFlushIfPossible() {
LOGV("both audio and video are flushed now.");
- mRenderer->signalTimeDiscontinuity();
+ if (mTimeDiscontinuityPending) {
+ mRenderer->signalTimeDiscontinuity();
+ mTimeDiscontinuityPending = false;
+ }
if (mAudioDecoder != NULL) {
mAudioDecoder->signalResume();
@@ -663,10 +682,15 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
bool formatChange =
- type == ATSParser::DISCONTINUITY_FORMATCHANGE;
+ (audio &&
+ (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT))
+ || (!audio &&
+ (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT));
+
+ bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0;
- LOGV("%s discontinuity (formatChange=%d)",
- audio ? "audio" : "video", formatChange);
+ LOGI("%s discontinuity (formatChange=%d, time=%d)",
+ audio ? "audio" : "video", formatChange, timeChange);
if (audio) {
mSkipRenderingAudioUntilMediaTimeUs = -1;
@@ -674,26 +698,45 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
mSkipRenderingVideoUntilMediaTimeUs = -1;
}
- sp<AMessage> extra;
- if (accessUnit->meta()->findMessage("extra", &extra)
- && extra != NULL) {
- int64_t resumeAtMediaTimeUs;
- if (extra->findInt64(
- "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
- LOGI("suppressing rendering of %s until %lld us",
- audio ? "audio" : "video", resumeAtMediaTimeUs);
-
- if (audio) {
- mSkipRenderingAudioUntilMediaTimeUs =
- resumeAtMediaTimeUs;
- } else {
- mSkipRenderingVideoUntilMediaTimeUs =
- resumeAtMediaTimeUs;
+ if (timeChange) {
+ sp<AMessage> extra;
+ if (accessUnit->meta()->findMessage("extra", &extra)
+ && extra != NULL) {
+ int64_t resumeAtMediaTimeUs;
+ if (extra->findInt64(
+ "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
+ LOGI("suppressing rendering of %s until %lld us",
+ audio ? "audio" : "video", resumeAtMediaTimeUs);
+
+ if (audio) {
+ mSkipRenderingAudioUntilMediaTimeUs =
+ resumeAtMediaTimeUs;
+ } else {
+ mSkipRenderingVideoUntilMediaTimeUs =
+ resumeAtMediaTimeUs;
+ }
}
}
}
- flushDecoder(audio, formatChange);
+ mTimeDiscontinuityPending =
+ mTimeDiscontinuityPending || timeChange;
+
+ if (formatChange || timeChange) {
+ flushDecoder(audio, formatChange);
+ } else {
+ // This stream is unaffected by the discontinuity
+
+ if (audio) {
+ mFlushingAudio = FLUSHED;
+ } else {
+ mFlushingVideo = FLUSHED;
+ }
+
+ finishFlushIfPossible();
+
+ return -EWOULDBLOCK;
+ }
}
reply->setInt32("err", err);
@@ -794,6 +837,11 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
}
void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
+ if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) {
+ LOGI("flushDecoder %s without decoder present",
+ audio ? "audio" : "video");
+ }
+
// Make sure we don't continue to scan sources until we finish flushing.
++mScanSourcesGeneration;
mScanSourcesPending = false;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index f23deea..ffc710e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -112,6 +112,10 @@ private:
SHUT_DOWN,
};
+ // Once the current flush is complete this indicates whether the
+ // notion of time has changed.
+ bool mTimeDiscontinuityPending;
+
FlushStatus mFlushingAudio;
FlushStatus mFlushingVideo;
bool mResetInProgress;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 640e9fa..0cb7f45 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -628,11 +628,16 @@ void NuPlayer::Renderer::onPause() {
mAudioSink->pause();
}
+ LOGV("now paused audio queue has %d entries, video has %d entries",
+ mAudioQueue.size(), mVideoQueue.size());
+
mPaused = true;
}
void NuPlayer::Renderer::onResume() {
- CHECK(mPaused);
+ if (!mPaused) {
+ return;
+ }
if (mHasAudio) {
mAudioSink->start();
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index f795654..2e63b3b 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -63,17 +63,22 @@ status_t NuPlayer::StreamingSource::feedMoreTSData() {
mFinalResult = ERROR_END_OF_STREAM;
break;
} else if (n == INFO_DISCONTINUITY) {
- ATSParser::DiscontinuityType type = ATSParser::DISCONTINUITY_SEEK;
+ int32_t type = ATSParser::DISCONTINUITY_SEEK;
- int32_t formatChange;
+ int32_t mask;
if (extra != NULL
&& extra->findInt32(
- IStreamListener::kKeyFormatChange, &formatChange)
- && formatChange != 0) {
- type = ATSParser::DISCONTINUITY_FORMATCHANGE;
+ IStreamListener::kKeyDiscontinuityMask, &mask)) {
+ if (mask == 0) {
+ LOGE("Client specified an illegal discontinuity type.");
+ return ERROR_UNSUPPORTED;
+ }
+
+ type = mask;
}
- mTSParser->signalDiscontinuity(type, extra);
+ mTSParser->signalDiscontinuity(
+ (ATSParser::DiscontinuityType)type, extra);
} else if (n < 0) {
CHECK_EQ(n, -EWOULDBLOCK);
break;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d947760..dbc9b7e 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -342,6 +342,7 @@ void ACodec::initiateSetup(const sp<AMessage> &msg) {
}
void ACodec::signalFlush() {
+ LOGV("[%s] signalFlush", mComponentName.c_str());
(new AMessage(kWhatFlush, id()))->post();
}
@@ -1092,6 +1093,20 @@ status_t ACodec::initNativeWindow() {
return OK;
}
+size_t ACodec::countBuffersOwnedByComponent(OMX_U32 portIndex) const {
+ size_t n = 0;
+
+ for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
+ const BufferInfo &info = mBuffers[portIndex].itemAt(i);
+
+ if (info.mStatus == BufferInfo::OWNED_BY_COMPONENT) {
+ ++n;
+ }
+ }
+
+ return n;
+}
+
bool ACodec::allYourBuffersAreBelongToUs(
OMX_U32 portIndex) {
for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
@@ -2041,6 +2056,14 @@ bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) {
case kWhatFlush:
{
+ LOGV("[%s] ExecutingState flushing now "
+ "(codec owns %d/%d input, %d/%d output).",
+ mCodec->mComponentName.c_str(),
+ mCodec->countBuffersOwnedByComponent(kPortIndexInput),
+ mCodec->mBuffers[kPortIndexInput].size(),
+ mCodec->countBuffersOwnedByComponent(kPortIndexOutput),
+ mCodec->mBuffers[kPortIndexOutput].size());
+
mActive = false;
CHECK_EQ(mCodec->mOMX->sendCommand(
@@ -2180,6 +2203,12 @@ bool ACodec::OutputPortSettingsChangedState::onOMXEvent(
err);
mCodec->signalError();
+
+ // This is technically not correct, since we were unable
+ // to allocate output buffers and therefore the output port
+ // remains disabled. It is necessary however to allow us
+ // to shutdown the codec properly.
+ mCodec->changeState(mCodec->mExecutingState);
}
return true;
@@ -2408,6 +2437,9 @@ bool ACodec::FlushingState::onMessageReceived(const sp<AMessage> &msg) {
bool ACodec::FlushingState::onOMXEvent(
OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
+ LOGV("[%s] FlushingState onOMXEvent(%d,%ld)",
+ mCodec->mComponentName.c_str(), event, data1);
+
switch (event) {
case OMX_EventCmdComplete:
{
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
index 0be2ca4..815f987 100644
--- a/media/libstagefright/AVIExtractor.cpp
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -1094,7 +1094,7 @@ status_t AVIExtractor::addH264CodecSpecificData(size_t trackIndex) {
CHECK(meta->findData(kKeyAVCC, &type, &csd, &csdSize));
track->mMeta->setInt32(kKeyWidth, width);
- track->mMeta->setInt32(kKeyHeight, width);
+ track->mMeta->setInt32(kKeyHeight, height);
track->mMeta->setData(kKeyAVCC, type, csd, csdSize);
return OK;
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 2b27ee2..86b33d1 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -336,7 +336,7 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
(uint32_t(buffer->height) != h) ||
(uint32_t(buffer->format) != format) ||
((uint32_t(buffer->usage) & usage) != usage)) {
- usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+ usage |= GraphicBuffer::USAGE_HW_VIDEO_ENCODER;
status_t error;
sp<GraphicBuffer> graphicBuffer(
mGraphicBufferAlloc->createGraphicBuffer(
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 72f1282..6cec63a 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -123,6 +123,9 @@ private:
void extractAACFrames(const sp<ABuffer> &buffer);
+ bool isAudio() const;
+ bool isVideo() const;
+
DISALLOW_EVIL_CONSTRUCTORS(Stream);
};
@@ -401,7 +404,7 @@ ATSParser::Stream::Stream(
case STREAMTYPE_H264:
mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::H264);
break;
- case STREAMTYPE_MPEG2_AUDIO_ATDS:
+ case STREAMTYPE_MPEG2_AUDIO_ADTS:
mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::AAC);
break;
case STREAMTYPE_MPEG1_AUDIO:
@@ -486,6 +489,31 @@ status_t ATSParser::Stream::parse(
return OK;
}
+bool ATSParser::Stream::isVideo() const {
+ switch (mStreamType) {
+ case STREAMTYPE_H264:
+ case STREAMTYPE_MPEG1_VIDEO:
+ case STREAMTYPE_MPEG2_VIDEO:
+ case STREAMTYPE_MPEG4_VIDEO:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool ATSParser::Stream::isAudio() const {
+ switch (mStreamType) {
+ case STREAMTYPE_MPEG1_AUDIO:
+ case STREAMTYPE_MPEG2_AUDIO:
+ case STREAMTYPE_MPEG2_AUDIO_ADTS:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
void ATSParser::Stream::signalDiscontinuity(
DiscontinuityType type, const sp<AMessage> &extra) {
if (mQueue == NULL) {
@@ -495,34 +523,34 @@ void ATSParser::Stream::signalDiscontinuity(
mPayloadStarted = false;
mBuffer->setRange(0, 0);
- switch (type) {
- case DISCONTINUITY_SEEK:
- case DISCONTINUITY_FORMATCHANGE:
- {
- bool isASeek = (type == DISCONTINUITY_SEEK);
-
- mQueue->clear(!isASeek);
+ bool clearFormat = false;
+ if (isAudio()) {
+ if (type & DISCONTINUITY_AUDIO_FORMAT) {
+ clearFormat = true;
+ }
+ } else {
+ if (type & DISCONTINUITY_VIDEO_FORMAT) {
+ clearFormat = true;
+ }
+ }
- uint64_t resumeAtPTS;
- if (extra != NULL
- && extra->findInt64(
- IStreamListener::kKeyResumeAtPTS,
- (int64_t *)&resumeAtPTS)) {
- int64_t resumeAtMediaTimeUs =
- mProgram->convertPTSToTimestamp(resumeAtPTS);
+ mQueue->clear(clearFormat);
- extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs);
- }
+ if (type & DISCONTINUITY_TIME) {
+ uint64_t resumeAtPTS;
+ if (extra != NULL
+ && extra->findInt64(
+ IStreamListener::kKeyResumeAtPTS,
+ (int64_t *)&resumeAtPTS)) {
+ int64_t resumeAtMediaTimeUs =
+ mProgram->convertPTSToTimestamp(resumeAtPTS);
- if (mSource != NULL) {
- mSource->queueDiscontinuity(type, extra);
- }
- break;
+ extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs);
}
+ }
- default:
- TRESPASS();
- break;
+ if (mSource != NULL) {
+ mSource->queueDiscontinuity(type, extra);
}
}
@@ -764,10 +792,7 @@ sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
switch (type) {
case VIDEO:
{
- if (mStreamType == STREAMTYPE_H264
- || mStreamType == STREAMTYPE_MPEG1_VIDEO
- || mStreamType == STREAMTYPE_MPEG2_VIDEO
- || mStreamType == STREAMTYPE_MPEG4_VIDEO) {
+ if (isVideo()) {
return mSource;
}
break;
@@ -775,9 +800,7 @@ sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
case AUDIO:
{
- if (mStreamType == STREAMTYPE_MPEG1_AUDIO
- || mStreamType == STREAMTYPE_MPEG2_AUDIO
- || mStreamType == STREAMTYPE_MPEG2_AUDIO_ATDS) {
+ if (isAudio()) {
return mSource;
}
break;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 878e534..c8038d1 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -33,9 +33,18 @@ struct MediaSource;
struct ATSParser : public RefBase {
enum DiscontinuityType {
- DISCONTINUITY_NONE,
- DISCONTINUITY_SEEK,
- DISCONTINUITY_FORMATCHANGE
+ DISCONTINUITY_NONE = 0,
+ DISCONTINUITY_TIME = 1,
+ DISCONTINUITY_AUDIO_FORMAT = 2,
+ DISCONTINUITY_VIDEO_FORMAT = 4,
+
+ DISCONTINUITY_SEEK = DISCONTINUITY_TIME,
+
+ // For legacy reasons this also implies a time discontinuity.
+ DISCONTINUITY_FORMATCHANGE =
+ DISCONTINUITY_AUDIO_FORMAT
+ | DISCONTINUITY_VIDEO_FORMAT
+ | DISCONTINUITY_TIME,
};
enum Flags {
@@ -71,7 +80,7 @@ struct ATSParser : public RefBase {
STREAMTYPE_MPEG2_VIDEO = 0x02,
STREAMTYPE_MPEG1_AUDIO = 0x03,
STREAMTYPE_MPEG2_AUDIO = 0x04,
- STREAMTYPE_MPEG2_AUDIO_ATDS = 0x0f,
+ STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f,
STREAMTYPE_MPEG4_VIDEO = 0x10,
STREAMTYPE_H264 = 0x1b,
};
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index ce07e32..f782ce5 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -29,8 +29,17 @@
namespace android {
AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta)
- : mFormat(meta),
+ : mIsAudio(false),
+ mFormat(meta),
mEOSResult(OK) {
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!strncasecmp("audio/", mime, 6)) {
+ mIsAudio = true;
+ } else {
+ CHECK(!strncasecmp("video/", mime, 6));
+ }
}
void AnotherPacketSource::setFormat(const sp<MetaData> &meta) {
@@ -67,8 +76,7 @@ status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) {
int32_t discontinuity;
if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) {
-
- if (discontinuity == ATSParser::DISCONTINUITY_FORMATCHANGE) {
+ if (wasFormatChange(discontinuity)) {
mFormat.clear();
}
@@ -96,7 +104,7 @@ status_t AnotherPacketSource::read(
int32_t discontinuity;
if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
- if (discontinuity == ATSParser::DISCONTINUITY_FORMATCHANGE) {
+ if (wasFormatChange(discontinuity)) {
mFormat.clear();
}
@@ -117,6 +125,15 @@ status_t AnotherPacketSource::read(
return mEOSResult;
}
+bool AnotherPacketSource::wasFormatChange(
+ int32_t discontinuityType) const {
+ if (mIsAudio) {
+ return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
+ }
+
+ return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0;
+}
+
void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
int32_t damaged;
if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index 439c785..c99f7f2 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -61,10 +61,13 @@ private:
Mutex mLock;
Condition mCondition;
+ bool mIsAudio;
sp<MetaData> mFormat;
List<sp<ABuffer> > mBuffers;
status_t mEOSResult;
+ bool wasFormatChange(int32_t discontinuityType) const;
+
DISALLOW_EVIL_CONSTRUCTORS(AnotherPacketSource);
};
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
index f55be6e..a089dbf 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -543,7 +543,7 @@ MPEG2PSExtractor::Track::Track(
case ATSParser::STREAMTYPE_H264:
mode = ElementaryStreamQueue::H264;
break;
- case ATSParser::STREAMTYPE_MPEG2_AUDIO_ATDS:
+ case ATSParser::STREAMTYPE_MPEG2_AUDIO_ADTS:
mode = ElementaryStreamQueue::AAC;
break;
case ATSParser::STREAMTYPE_MPEG1_AUDIO:
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
index 3fb2da0..92ac9eb 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
@@ -39,6 +39,7 @@ import com.android.mediaframeworktest.functional.videoeditor.VideoEditorExportTe
import com.android.mediaframeworktest.functional.videoeditor.VideoEditorPreviewTest;
import junit.framework.TestSuite;
+import android.os.Bundle;
import android.test.InstrumentationTestRunner;
import android.test.InstrumentationTestSuite;
@@ -54,6 +55,7 @@ import android.test.InstrumentationTestSuite;
public class MediaFrameworkTestRunner extends InstrumentationTestRunner {
+ public static int mMinCameraFps = 0;
@Override
public TestSuite getAllTests() {
@@ -87,4 +89,16 @@ public class MediaFrameworkTestRunner extends InstrumentationTestRunner {
public ClassLoader getLoader() {
return MediaFrameworkTestRunner.class.getClassLoader();
}
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ String minCameraFps = (String) icicle.get("min_camera_fps");
+ System.out.print("min_camera_" + minCameraFps);
+
+ if (minCameraFps != null ) {
+ mMinCameraFps = Integer.parseInt(minCameraFps);
+ }
+ }
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
index b5c8c8c..0684946 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
@@ -33,6 +33,7 @@ import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.android.mediaframeworktest.MediaProfileReader;
+import com.android.mediaframeworktest.MediaFrameworkTestRunner;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
@@ -115,9 +116,16 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaFra
int audioChannels = highQuality? audioCap.mMaxChannels: audioCap.mMinChannels ;
int audioSamplingRate = highQuality? audioCap.mMaxSampleRate: audioCap.mMinSampleRate;
+ //Overide the fps if the min_camera_fps is set
+ if (MediaFrameworkTestRunner.mMinCameraFps != 0 &&
+ MediaFrameworkTestRunner.mMinCameraFps > videoFps){
+ videoFps = MediaFrameworkTestRunner.mMinCameraFps;
+ }
+
if (videoFps < MIN_VIDEO_FPS) {
videoFps = MIN_VIDEO_FPS;
}
+
mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
String filename = ("/sdcard/" + videoEncoder + "_" + audioEncoder + "_" + highQuality + ".3gp");
try {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 0b887b9..4f6e7d2 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -37,11 +37,13 @@ import android.util.Log;
import android.view.SurfaceHolder;
import java.util.List;
+import java.io.BufferedReader;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.Writer;
import java.io.File;
import java.io.FileWriter;
@@ -68,6 +70,8 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
private static final long MEDIA_STRESS_WAIT_TIME = 5000; //5 seconds
private static final String MEDIA_MEMORY_OUTPUT =
"/sdcard/mediaMemOutput.txt";
+ private static final String MEDIA_PROCMEM_OUTPUT =
+ "/sdcard/mediaProcmemOutput.txt";
private static int mStartMemory = 0;
private static int mEndMemory = 0;
@@ -84,6 +88,9 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
private static int DECODER_LIMIT = 150;
private static int CAMERA_LIMIT = 80;
+ private Writer mProcMemWriter;
+ private Writer mMemWriter;
+
private static List<VideoEncoderCap> videoEncoders = MediaProfileReader.getVideoEncoders();
Camera mCamera;
@@ -97,12 +104,21 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
getActivity();
if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump)
MediaTestUtil.getNativeHeapDump(this.getName() + "_before");
+
+ mProcMemWriter = new BufferedWriter(new FileWriter
+ (new File(MEDIA_PROCMEM_OUTPUT), true));
+ mProcMemWriter.write(this.getName() + "\n");
+ mMemWriter = new BufferedWriter(new FileWriter
+ (new File(MEDIA_MEMORY_OUTPUT), true));
+
}
protected void tearDown() throws Exception {
- super.tearDown();
if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump)
MediaTestUtil.getNativeHeapDump(this.getName() + "_after");
+ mProcMemWriter.close();
+ mMemWriter.close();
+ super.tearDown();
}
private void initializeMessageLooper() {
@@ -247,24 +263,39 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
}
//Write the ps output to the file
- public void getMemoryWriteToLog(Writer output, int writeCount) {
+ public void getMemoryWriteToLog(int writeCount) {
String memusage = null;
try {
if (writeCount == 0) {
mStartMemory = getMediaserverVsize();
- output.write("Start memory : " + mStartMemory + "\n");
+ mMemWriter.write("Start memory : " + mStartMemory + "\n");
}
memusage = captureMediaserverInfo();
- output.write(memusage);
+ mMemWriter.write(memusage);
if (writeCount == NUM_STRESS_LOOP - 1) {
mEndMemory = getMediaserverVsize();
- output.write("End Memory :" + mEndMemory + "\n");
+ mMemWriter.write("End Memory :" + mEndMemory + "\n");
}
} catch (Exception e) {
e.toString();
}
}
+ public void writeProcmemInfo() throws Exception{
+ String cmd = "procmem " + getMediaserverPid();
+ Process p = Runtime.getRuntime().exec(cmd);
+
+ InputStream inStream = p.getInputStream();
+ InputStreamReader inReader = new InputStreamReader(inStream);
+ BufferedReader inBuffer = new BufferedReader(inReader);
+ String s;
+ while ((s = inBuffer.readLine()) != null) {
+ mProcMemWriter.write(s);
+ mProcMemWriter.write("\n");
+ }
+ mProcMemWriter.write("\n\n");
+ }
+
public String captureMediaserverInfo() {
String cm = "ps mediaserver";
String memoryUsage = null;
@@ -306,7 +337,7 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
return vsizevalue;
}
- public boolean validateMemoryResult(int startPid, int startMemory, Writer output, int limit)
+ public boolean validateMemoryResult(int startPid, int startMemory, int limit)
throws Exception {
// Wait for 10 seconds to make sure the memory settle.
Thread.sleep(10000);
@@ -315,11 +346,11 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
if (memDiff < 0) {
memDiff = 0;
}
- output.write("The total diff = " + memDiff);
- output.write("\n\n");
+ mMemWriter.write("The total diff = " + memDiff);
+ mMemWriter.write("\n\n");
// mediaserver crash
if (startPid != mEndPid) {
- output.write("mediaserver died. Test failed\n");
+ mMemWriter.write("mediaserver died. Test failed\n");
return false;
}
// memory leak greter than the tolerant
@@ -331,18 +362,16 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
@LargeTest
public void testH263VideoPlaybackMemoryUsage() throws Exception {
boolean memoryResult = false;
- mStartPid = getMediaserverPid();
- File h263MemoryOut = new File(MEDIA_MEMORY_OUTPUT);
- Writer output = new BufferedWriter(new FileWriter(h263MemoryOut, true));
- output.write("H263 Video Playback Only\n");
+ mStartPid = getMediaserverPid();
+ mMemWriter.write("H263 Video Playback Only\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
mediaStressPlayback(MediaNames.VIDEO_HIGHRES_H263);
- getMemoryWriteToLog(output, i);
+ getMemoryWriteToLog(i);
+ writeProcmemInfo();
}
- output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT);
- output.close();
+ mMemWriter.write("\n");
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, DECODER_LIMIT);
assertTrue("H263 playback memory test", memoryResult);
}
@@ -350,18 +379,16 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
@LargeTest
public void testH264VideoPlaybackMemoryUsage() throws Exception {
boolean memoryResult = false;
- mStartPid = getMediaserverPid();
- File h264MemoryOut = new File(MEDIA_MEMORY_OUTPUT);
- Writer output = new BufferedWriter(new FileWriter(h264MemoryOut, true));
- output.write("H264 Video Playback only\n");
+ mStartPid = getMediaserverPid();
+ mMemWriter.write("H264 Video Playback only\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
mediaStressPlayback(MediaNames.VIDEO_H264_AMR);
- getMemoryWriteToLog(output, i);
+ getMemoryWriteToLog(i);
+ writeProcmemInfo();
}
- output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT);
- output.close();
+ mMemWriter.write("\n");
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, DECODER_LIMIT);
assertTrue("H264 playback memory test", memoryResult);
}
@@ -369,21 +396,19 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
@LargeTest
public void testH263RecordVideoOnlyMemoryUsage() throws Exception {
boolean memoryResult = false;
- mStartPid = getMediaserverPid();
- File videoH263RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
- Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut, true));
- output.write("H263 video record only\n");
+ mStartPid = getMediaserverPid();
+ mMemWriter.write("H263 video record only\n");
int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
assertTrue("H263 video recording frame rate", frameRate != -1);
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.H263,
MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true));
- getMemoryWriteToLog(output, i);
+ getMemoryWriteToLog(i);
+ writeProcmemInfo();
}
- output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT);
- output.close();
+ mMemWriter.write("\n");
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
assertTrue("H263 record only memory test", memoryResult);
}
@@ -391,21 +416,19 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
@LargeTest
public void testMpeg4RecordVideoOnlyMemoryUsage() throws Exception {
boolean memoryResult = false;
- mStartPid = getMediaserverPid();
- File videoMp4RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
- Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut, true));
- output.write("MPEG4 video record only\n");
+ mStartPid = getMediaserverPid();
+ mMemWriter.write("MPEG4 video record only\n");
int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.MPEG_4_SP);
assertTrue("MPEG4 video recording frame rate", frameRate != -1);
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP,
MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true));
- getMemoryWriteToLog(output, i);
+ getMemoryWriteToLog(i);
+ writeProcmemInfo();
}
- output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT);
- output.close();
+ mMemWriter.write("\n");
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
assertTrue("mpeg4 record only memory test", memoryResult);
}
@@ -414,21 +437,19 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
@LargeTest
public void testRecordVideoAudioMemoryUsage() throws Exception {
boolean memoryResult = false;
- mStartPid = getMediaserverPid();
- File videoRecordAudioMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
- Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut, true));
+ mStartPid = getMediaserverPid();
int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
assertTrue("H263 video recording frame rate", frameRate != -1);
- output.write("Audio and h263 video record\n");
+ mMemWriter.write("Audio and h263 video record\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.H263,
MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false));
- getMemoryWriteToLog(output, i);
+ getMemoryWriteToLog(i);
+ writeProcmemInfo();
}
- output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT);
- output.close();
+ mMemWriter.write("\n");
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
assertTrue("H263 audio video record memory test", memoryResult);
}
@@ -436,18 +457,16 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
@LargeTest
public void testRecordAudioOnlyMemoryUsage() throws Exception {
boolean memoryResult = false;
- mStartPid = getMediaserverPid();
- File audioOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
- Writer output = new BufferedWriter(new FileWriter(audioOnlyMemoryOut, true));
- output.write("Audio record only\n");
+ mStartPid = getMediaserverPid();
+ mMemWriter.write("Audio record only\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
stressAudioRecord(MediaNames.RECORDER_OUTPUT);
- getMemoryWriteToLog(output, i);
+ getMemoryWriteToLog(i);
+ writeProcmemInfo();
}
- output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT);
- output.close();
+ mMemWriter.write("\n");
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
assertTrue("audio record only memory test", memoryResult);
}
@@ -455,18 +474,16 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
@LargeTest
public void testCameraPreviewMemoryUsage() throws Exception {
boolean memoryResult = false;
- mStartPid = getMediaserverPid();
- File cameraPreviewMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
- Writer output = new BufferedWriter(new FileWriter(cameraPreviewMemoryOut, true));
- output.write("Camera Preview Only\n");
+ mStartPid = getMediaserverPid();
+ mMemWriter.write("Camera Preview Only\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
stressCameraPreview();
- getMemoryWriteToLog(output, i);
+ getMemoryWriteToLog(i);
+ writeProcmemInfo();
}
- output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, CAMERA_LIMIT);
- output.close();
+ mMemWriter.write("\n");
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, CAMERA_LIMIT);
assertTrue("camera preview memory test", memoryResult);
}
}
diff --git a/native/include/android/keycodes.h b/native/include/android/keycodes.h
index 5d49775..8414ff6 100644
--- a/native/include/android/keycodes.h
+++ b/native/include/android/keycodes.h
@@ -250,6 +250,10 @@ enum {
AKEYCODE_LANGUAGE_SWITCH = 204,
AKEYCODE_MANNER_MODE = 205,
AKEYCODE_3D_MODE = 206,
+ AKEYCODE_CONTACTS = 207,
+ AKEYCODE_CALENDAR = 208,
+ AKEYCODE_MUSIC = 209,
+ AKEYCODE_CALCULATOR = 210,
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index a63d5b0..2b0ed5d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -49,6 +49,8 @@ using namespace android;
// ----------------------------------------------------------------------------
+#define EGL_VERSION_HW_ANDROID 0x3143
+
struct extention_map_t {
const char* name;
__eglMustCastToProperFunctionPointerType address;
@@ -972,6 +974,12 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name)
return dp->getExtensionString();
case EGL_CLIENT_APIS:
return dp->getClientApiString();
+ case EGL_VERSION_HW_ANDROID: {
+ if (gEGLImpl[IMPL_HARDWARE].dso) {
+ return dp->disp[IMPL_HARDWARE].queryString.version;
+ }
+ return dp->disp[IMPL_SOFTWARE].queryString.version;
+ }
}
return setError(EGL_BAD_PARAMETER, (const char *)0);
}
diff --git a/opengl/specs/README b/opengl/specs/README
index 2fa2587..16b278f 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -9,4 +9,5 @@ for use by Android extensions.
0x3140 EGL_ANDROID_image_native_buffer
0x3141 (unused)
0x3142 EGL_ANDROID_recordable
-0x3143 - 0x314F (unused)
+0x3143 EGL_VERSION_HW_ANDROID (internal use)
+0x3144 - 0x314F (unused)
diff --git a/packages/SettingsProvider/res/values-vi/strings.xml b/packages/SettingsProvider/res/values-vi/strings.xml
index 113d7ad..504479d 100644
--- a/packages/SettingsProvider/res/values-vi/strings.xml
+++ b/packages/SettingsProvider/res/values-vi/strings.xml
@@ -19,5 +19,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4567566098528588863">"Bộ nhớ Cài đặt"</string>
+ <string name="app_label" msgid="4567566098528588863">"Lưu trữ cài đặt"</string>
</resources>
diff --git a/packages/SettingsProvider/res/xml/bookmarks.xml b/packages/SettingsProvider/res/xml/bookmarks.xml
index 83229f4..454f456 100644
--- a/packages/SettingsProvider/res/xml/bookmarks.xml
+++ b/packages/SettingsProvider/res/xml/bookmarks.xml
@@ -19,6 +19,7 @@
Bookmarks for vendor apps should be added to a bookmarks resource overlay; not here.
Typical shortcuts (not necessarily defined here):
+ 'a': Calculator
'b': Browser
'c': Contacts
'e': Email
@@ -32,27 +33,27 @@
-->
<bookmarks>
<bookmark
- package="com.android.browser"
- class="com.android.browser.BrowserActivity"
+ category="android.intent.category.APP_CALCULATOR"
+ shortcut="a" />
+ <bookmark
+ category="android.intent.category.APP_BROWSER"
shortcut="b" />
<bookmark
- package="com.android.contacts"
- class="com.android.contacts.activities.ContactsFrontDoor"
+ category="android.intent.category.APP_CONTACTS"
shortcut="c" />
<bookmark
- package="com.google.android.email"
- class="com.android.email.activity.Welcome"
+ category="android.intent.category.APP_EMAIL"
shortcut="e" />
<bookmark
- package="com.google.android.calendar"
- class="com.android.calendar.LaunchActivity"
+ category="android.intent.category.APP_CALENDAR"
shortcut="l" />
<bookmark
- package="com.android.music"
- class="com.android.music.MusicBrowserActivity"
+ category="android.intent.category.APP_MAPS"
+ shortcut="m" />
+ <bookmark
+ category="android.intent.category.APP_MUSIC"
shortcut="p" />
<bookmark
- package="com.android.mms"
- class="com.android.mms.ui.ConversationList"
+ category="android.intent.category.APP_MESSAGING"
shortcut="s" />
</bookmarks>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index aa08e64..080d345 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -63,7 +63,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 70;
+ private static final int DATABASE_VERSION = 71;
private Context mContext;
@@ -946,6 +946,12 @@ public class DatabaseHelper extends SQLiteOpenHelper {
upgradeVersion = 70;
}
+ if (upgradeVersion == 70) {
+ // Update all built-in bookmarks. Some of the package names have changed.
+ loadBookmarks(db);
+ upgradeVersion = 71;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -1086,16 +1092,11 @@ public class DatabaseHelper extends SQLiteOpenHelper {
* Loads the default set of bookmarked shortcuts from an xml file.
*
* @param db The database to write the values into
- * @param startingIndex The zero-based position at which bookmarks in this file should begin
*/
- private int loadBookmarks(SQLiteDatabase db, int startingIndex) {
- Intent intent = new Intent(Intent.ACTION_MAIN, null);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ private void loadBookmarks(SQLiteDatabase db) {
ContentValues values = new ContentValues();
PackageManager packageManager = mContext.getPackageManager();
- int i = startingIndex;
-
try {
XmlResourceParser parser = mContext.getResources().getXml(R.xml.bookmarks);
XmlUtils.beginDocument(parser, "bookmarks");
@@ -1118,54 +1119,60 @@ public class DatabaseHelper extends SQLiteOpenHelper {
String pkg = parser.getAttributeValue(null, "package");
String cls = parser.getAttributeValue(null, "class");
String shortcutStr = parser.getAttributeValue(null, "shortcut");
+ String category = parser.getAttributeValue(null, "category");
int shortcutValue = shortcutStr.charAt(0);
if (TextUtils.isEmpty(shortcutStr)) {
Log.w(TAG, "Unable to get shortcut for: " + pkg + "/" + cls);
+ continue;
}
- ActivityInfo info = null;
- ComponentName cn = new ComponentName(pkg, cls);
- try {
- info = packageManager.getActivityInfo(cn, 0);
- } catch (PackageManager.NameNotFoundException e) {
- String[] packages = packageManager.canonicalToCurrentPackageNames(
- new String[] { pkg });
- cn = new ComponentName(packages[0], cls);
+ final Intent intent;
+ final String title;
+ if (pkg != null && cls != null) {
+ ActivityInfo info = null;
+ ComponentName cn = new ComponentName(pkg, cls);
try {
info = packageManager.getActivityInfo(cn, 0);
- } catch (PackageManager.NameNotFoundException e1) {
- Log.w(TAG, "Unable to add bookmark: " + pkg + "/" + cls, e);
+ } catch (PackageManager.NameNotFoundException e) {
+ String[] packages = packageManager.canonicalToCurrentPackageNames(
+ new String[] { pkg });
+ cn = new ComponentName(packages[0], cls);
+ try {
+ info = packageManager.getActivityInfo(cn, 0);
+ } catch (PackageManager.NameNotFoundException e1) {
+ Log.w(TAG, "Unable to add bookmark: " + pkg + "/" + cls, e);
+ continue;
+ }
}
- }
-
- if (info != null) {
+
+ intent = new Intent(Intent.ACTION_MAIN, null);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setComponent(cn);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- values.put(Settings.Bookmarks.INTENT, intent.toUri(0));
- values.put(Settings.Bookmarks.TITLE,
- info.loadLabel(packageManager).toString());
- values.put(Settings.Bookmarks.SHORTCUT, shortcutValue);
- db.insert("bookmarks", null, values);
- i++;
+ title = info.loadLabel(packageManager).toString();
+ } else if (category != null) {
+ intent = new Intent(Intent.ACTION_MAIN, null);
+ intent.addCategory(category);
+ title = "";
+ } else {
+ Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutStr
+ + ": missing package/class or category attributes");
+ continue;
}
+
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ values.put(Settings.Bookmarks.INTENT, intent.toUri(0));
+ values.put(Settings.Bookmarks.TITLE, title);
+ values.put(Settings.Bookmarks.SHORTCUT, shortcutValue);
+ db.delete("bookmarks", "shortcut = ?",
+ new String[] { Integer.toString(shortcutValue) });
+ db.insert("bookmarks", null, values);
}
} catch (XmlPullParserException e) {
Log.w(TAG, "Got execption parsing bookmarks.", e);
} catch (IOException e) {
Log.w(TAG, "Got execption parsing bookmarks.", e);
}
-
- return i;
- }
-
- /**
- * Loads the default set of bookmark packages.
- *
- * @param db The database to write the values into
- */
- private void loadBookmarks(SQLiteDatabase db) {
- loadBookmarks(db, 0);
}
/**
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e937587..ec08e6c 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -46,26 +46,6 @@
</intent-filter>
</receiver>
- <!-- should you need to launch the screensaver, this is a good way to do it -->
- <activity android:name=".DreamsDockLauncher"
- android:theme="@android:style/Theme.Dialog"
- android:label="@string/dreams_dock_launcher">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
- <!-- launch screensaver on (desk) dock event -->
- <receiver android:name=".DreamsDockLauncher$DockEventReceiver"
- android:exported="true"
- >
- <intent-filter>
- <action android:name="android.intent.action.DOCK_EVENT" />
- </intent-filter>
- </receiver>
-
-
<activity android:name=".usb.UsbStorageActivity"
android:label="@*android:string/usb_storage_activity_title"
android:excludeFromRecents="true">
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index d416af9..8b337ea 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -19,23 +19,18 @@
<ImageView android:id="@+id/global_screenshot_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="#FF000000"
+ android:src="@android:color/black"
android:visibility="gone" />
- <FrameLayout
- android:id="@+id/global_screenshot_container"
+ <ImageView android:id="@+id/global_screenshot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/screenshot_panel"
- android:visibility="gone">
- <ImageView android:id="@+id/global_screenshot"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:adjustViewBounds="true" />
- </FrameLayout>
+ android:visibility="gone"
+ android:adjustViewBounds="true" />
<ImageView android:id="@+id/global_screenshot_flash"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="#FFFFFFFF"
+ android:src="@android:color/white"
android:visibility="gone" />
</FrameLayout>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index df46d26..d313517 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -106,7 +106,7 @@
<string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"Signal WiMAX : faible"</string>
<string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"Signal WiMAX : moyen"</string>
<string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"Signal WiMAX : bon"</string>
- <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"Signal WiMAX excellent"</string>
+ <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"Signal WiMAX : excellent"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string>
<string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3G+"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 6e94cc5..17330b1 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -131,7 +131,7 @@
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" удалено из списка."</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Передача данных по каналам 2G и 3G отключена"</string>
<string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Передача данных по каналу 4G отключена"</string>
- <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Мобильный Интернет отключен"</string>
+ <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Моб. Интернет отключен"</string>
<string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Передача данных отключена"</string>
<string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Достигнут лимит трафика."\n\n"При восстановлении подключения оператор может взимать плату за передачу данных."</string>
<string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Восстановить подключение"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fc81f8e..2c1473b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -362,7 +362,4 @@
<!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_clear_all">Clear all notifications.</string>
-
- <!-- Description of the desk dock action that invokes the Android Dreams screen saver feature -->
- <string name="dreams_dock_launcher">Activate screen saver</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/DreamsDockLauncher.java b/packages/SystemUI/src/com/android/systemui/DreamsDockLauncher.java
deleted file mode 100644
index 1db2a7f..0000000
--- a/packages/SystemUI/src/com/android/systemui/DreamsDockLauncher.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package com.android.systemui;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.util.Slog;
-
-public class DreamsDockLauncher extends Activity {
- private static final String TAG = "DreamsDockLauncher";
-
- // Launch the screen saver if started as an activity.
- @Override
- protected void onCreate (Bundle icicle) {
- super.onCreate(icicle);
- launchDream(this);
- finish();
- }
-
- private static void launchDream(Context context) {
- try {
- String component = Settings.Secure.getString(
- context.getContentResolver(), Settings.Secure.SCREENSAVER_COMPONENT);
- if (component == null) {
- component = context.getResources().getString(
- com.android.internal.R.string.config_defaultDreamComponent);
- }
- if (component != null) {
- // dismiss the notification shade, recents, etc.
- context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
-
- ComponentName cn = ComponentName.unflattenFromString(component);
- Intent zzz = new Intent(Intent.ACTION_MAIN)
- .setComponent(cn)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_NO_USER_ACTION
- | Intent.FLAG_FROM_BACKGROUND
- | Intent.FLAG_ACTIVITY_NO_HISTORY
- );
- Slog.v(TAG, "Starting screen saver on dock event: " + component);
- context.startActivity(zzz);
- } else {
- Slog.e(TAG, "Couldn't start screen saver: none selected");
- }
- } catch (android.content.ActivityNotFoundException exc) {
- // no screensaver? give up
- Slog.e(TAG, "Couldn't start screen saver: none installed");
- }
- }
-
- // Trap low-level dock events and launch the screensaver.
- public static class DockEventReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- final boolean activateOnDock = 0 != Settings.Secure.getInt(
- context.getContentResolver(),
- Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, 1);
-
- if (!activateOnDock) return;
-
- if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
- Bundle extras = intent.getExtras();
- int state = extras
- .getInt(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
- if (state == Intent.EXTRA_DOCK_STATE_DESK
- || state == Intent.EXTRA_DOCK_STATE_LE_DESK
- || state == Intent.EXTRA_DOCK_STATE_HE_DESK) {
- launchDream(context);
- }
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index ad37603..2232995 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -34,15 +34,14 @@ import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.PointF;
+import android.hardware.CameraSound;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Process;
-import android.os.ServiceManager;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.view.Display;
-import android.view.IWindowManager;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
@@ -50,7 +49,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.systemui.R;
@@ -77,7 +75,6 @@ class SaveImageInBackgroundData {
*/
class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void,
SaveImageInBackgroundData> {
- private static final String TAG = "SaveImageInBackgroundTask";
private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
private static final String SCREENSHOT_FILE_PATH_TEMPLATE = "%s/%s/%s";
@@ -85,11 +82,8 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
private int mNotificationId;
private NotificationManager mNotificationManager;
private Notification.Builder mNotificationBuilder;
- private Intent mLaunchIntent;
- private String mImageDir;
private String mImageFileName;
private String mImageFilePath;
- private String mImageDate;
private long mImageTime;
// WORKAROUND: We want the same notification across screenshots that we update so that we don't
@@ -105,11 +99,11 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
// Prepare all the output metadata
mImageTime = System.currentTimeMillis();
- mImageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(mImageTime));
- mImageDir = Environment.getExternalStoragePublicDirectory(
+ String imageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(mImageTime));
+ String imageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES).getAbsolutePath();
- mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, mImageDate);
- mImageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE, mImageDir,
+ mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);
+ mImageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE, imageDir,
SCREENSHOTS_DIR_NAME, mImageFileName);
// Create the large notification icon
@@ -190,7 +184,7 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
}
return params[0];
- };
+ }
@Override
protected void onPostExecute(SaveImageInBackgroundData params) {
@@ -202,14 +196,14 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
Resources r = params.context.getResources();
// Create the intent to show the screenshot in gallery
- mLaunchIntent = new Intent(Intent.ACTION_VIEW);
- mLaunchIntent.setDataAndType(params.imageUri, "image/png");
- mLaunchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Intent launchIntent = new Intent(Intent.ACTION_VIEW);
+ launchIntent.setDataAndType(params.imageUri, "image/png");
+ launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mNotificationBuilder
.setContentTitle(r.getString(R.string.screenshot_saved_title))
.setContentText(r.getString(R.string.screenshot_saved_text))
- .setContentIntent(PendingIntent.getActivity(params.context, 0, mLaunchIntent, 0))
+ .setContentIntent(PendingIntent.getActivity(params.context, 0, launchIntent, 0))
.setWhen(System.currentTimeMillis())
.setAutoCancel(true);
@@ -218,7 +212,7 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
mNotificationManager.notify(mNotificationId, n);
}
params.finisher.run();
- };
+ }
}
/**
@@ -228,7 +222,6 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
* type of gallery?
*/
class GlobalScreenshot {
- private static final String TAG = "GlobalScreenshot";
private static final int SCREENSHOT_NOTIFICATION_ID = 789;
private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
private static final int SCREENSHOT_DROP_IN_DURATION = 430;
@@ -244,8 +237,6 @@ class GlobalScreenshot {
private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f;
private Context mContext;
- private LayoutInflater mLayoutInflater;
- private IWindowManager mIWindowManager;
private WindowManager mWindowManager;
private WindowManager.LayoutParams mWindowLayoutParams;
private NotificationManager mNotificationManager;
@@ -256,7 +247,6 @@ class GlobalScreenshot {
private Bitmap mScreenBitmap;
private View mScreenshotLayout;
private ImageView mBackgroundView;
- private FrameLayout mScreenshotContainerView;
private ImageView mScreenshotView;
private ImageView mScreenshotFlash;
@@ -266,6 +256,8 @@ class GlobalScreenshot {
private float mBgPadding;
private float mBgPaddingScale;
+ private CameraSound mCameraSound;
+
/**
* @param context everything needs a context :(
@@ -273,14 +265,13 @@ class GlobalScreenshot {
public GlobalScreenshot(Context context) {
Resources r = context.getResources();
mContext = context;
- mLayoutInflater = (LayoutInflater)
+ LayoutInflater layoutInflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Inflate the screenshot layout
mDisplayMatrix = new Matrix();
- mScreenshotLayout = mLayoutInflater.inflate(R.layout.global_screenshot, null);
+ mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);
mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
- mScreenshotContainerView = (FrameLayout) mScreenshotLayout.findViewById(R.id.global_screenshot_container);
mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
mScreenshotLayout.setFocusable(true);
@@ -293,8 +284,6 @@ class GlobalScreenshot {
});
// Setup the window that we are going to use
- mIWindowManager = IWindowManager.Stub.asInterface(
- ServiceManager.getService(Context.WINDOW_SERVICE));
mWindowLayoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
@@ -318,6 +307,9 @@ class GlobalScreenshot {
// Scale has to account for both sides of the bg
mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding);
mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;
+
+ // Setup the Camera shutter sound
+ mCameraSound = new CameraSound();
}
/**
@@ -428,8 +420,11 @@ class GlobalScreenshot {
mScreenshotLayout.post(new Runnable() {
@Override
public void run() {
- mScreenshotContainerView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- mScreenshotContainerView.buildLayer();
+ // Play the shutter sound to notify that we've taken a screenshot
+ mCameraSound.playSound(CameraSound.SHUTTER_CLICK);
+
+ mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mScreenshotView.buildLayer();
mScreenshotAnimation.start();
}
});
@@ -463,20 +458,16 @@ class GlobalScreenshot {
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- mBackgroundView.setFastAlpha(0f);
+ mBackgroundView.setAlpha(0f);
mBackgroundView.setVisibility(View.VISIBLE);
- mBackgroundView.fastInvalidate();
- mScreenshotContainerView.setFastAlpha(0f);
- mScreenshotContainerView.setFastTranslationX(0f);
- mScreenshotContainerView.setFastTranslationY(0f);
- mScreenshotContainerView.setFastScaleX(SCREENSHOT_SCALE + mBgPaddingScale);
- mScreenshotContainerView.setFastScaleY(SCREENSHOT_SCALE + mBgPaddingScale);
- mScreenshotContainerView.setVisibility(View.VISIBLE);
- mScreenshotContainerView.fastInvalidate();
- mScreenshotFlash.setFastAlpha(0f);
+ mScreenshotView.setAlpha(0f);
+ mScreenshotView.setTranslationX(0f);
+ mScreenshotView.setTranslationY(0f);
+ mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale);
+ mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale);
+ mScreenshotView.setVisibility(View.VISIBLE);
+ mScreenshotFlash.setAlpha(0f);
mScreenshotFlash.setVisibility(View.VISIBLE);
- mScreenshotFlash.fastInvalidate();
- mScreenshotLayout.invalidate();
}
@Override
public void onAnimationEnd(android.animation.Animator animation) {
@@ -486,19 +477,15 @@ class GlobalScreenshot {
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- float t = ((Float) animation.getAnimatedValue()).floatValue();
+ float t = (Float) animation.getAnimatedValue();
float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)
- - (float) scaleInterpolator.getInterpolation(t)
+ - scaleInterpolator.getInterpolation(t)
* (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);
- mBackgroundView.setFastAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
- mBackgroundView.fastInvalidate();
- mScreenshotContainerView.setFastAlpha(t);
- mScreenshotContainerView.setFastScaleX(scaleT);
- mScreenshotContainerView.setFastScaleY(scaleT);
- mScreenshotContainerView.fastInvalidate();
- mScreenshotFlash.setFastAlpha(flashAlphaInterpolator.getInterpolation(t));
- mScreenshotFlash.fastInvalidate();
- mScreenshotLayout.invalidate();
+ mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
+ mScreenshotView.setAlpha(t);
+ mScreenshotView.setScaleX(scaleT);
+ mScreenshotView.setScaleY(scaleT);
+ mScreenshotFlash.setAlpha(flashAlphaInterpolator.getInterpolation(t));
}
});
return anim;
@@ -511,8 +498,8 @@ class GlobalScreenshot {
@Override
public void onAnimationEnd(Animator animation) {
mBackgroundView.setVisibility(View.GONE);
- mScreenshotContainerView.setVisibility(View.GONE);
- mScreenshotContainerView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mScreenshotView.setVisibility(View.GONE);
+ mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
}
});
@@ -522,17 +509,13 @@ class GlobalScreenshot {
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- float t = ((Float) animation.getAnimatedValue()).floatValue();
+ float t = (Float) animation.getAnimatedValue();
float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
- - (float) t * (SCREENSHOT_DROP_IN_MIN_SCALE
- - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
- mBackgroundView.setFastAlpha((1f - t) * BACKGROUND_ALPHA);
- mBackgroundView.fastInvalidate();
- mScreenshotContainerView.setFastAlpha(1f - t);
- mScreenshotContainerView.setFastScaleX(scaleT);
- mScreenshotContainerView.setFastScaleY(scaleT);
- mScreenshotContainerView.fastInvalidate();
- mScreenshotLayout.invalidate();
+ - t * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
+ mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
+ mScreenshotView.setAlpha(1f - t);
+ mScreenshotView.setScaleX(scaleT);
+ mScreenshotView.setScaleY(scaleT);
}
});
} else {
@@ -563,19 +546,16 @@ class GlobalScreenshot {
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- float t = ((Float) animation.getAnimatedValue()).floatValue();
+ float t = (Float) animation.getAnimatedValue();
float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
- - (float) scaleInterpolator.getInterpolation(t)
+ - scaleInterpolator.getInterpolation(t)
* (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE);
- mBackgroundView.setFastAlpha((1f - t) * BACKGROUND_ALPHA);
- mBackgroundView.fastInvalidate();
- mScreenshotContainerView.setFastAlpha(1f - scaleInterpolator.getInterpolation(t));
- mScreenshotContainerView.setFastScaleX(scaleT);
- mScreenshotContainerView.setFastScaleY(scaleT);
- mScreenshotContainerView.setFastTranslationX(t * finalPos.x);
- mScreenshotContainerView.setFastTranslationY(t * finalPos.y);
- mScreenshotContainerView.fastInvalidate();
- mScreenshotLayout.invalidate();
+ mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
+ mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t));
+ mScreenshotView.setScaleX(scaleT);
+ mScreenshotView.setScaleY(scaleT);
+ mScreenshotView.setTranslationX(t * finalPos.x);
+ mScreenshotView.setTranslationY(t * finalPos.y);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 694da20..97a1855 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -20,6 +20,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Rect;
import android.os.ServiceManager;
import android.util.AttributeSet;
import android.util.Slog;
@@ -32,6 +33,10 @@ import android.view.Surface;
import android.view.WindowManager;
import android.widget.LinearLayout;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.StringBuilder;
+
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
@@ -237,4 +242,79 @@ public class NavigationBarView extends LinearLayout {
Slog.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
}
}
+
+ private String getResourceName(int resId) {
+ if (resId != 0) {
+ final android.content.res.Resources res = mContext.getResources();
+ try {
+ return res.getResourceName(resId);
+ } catch (android.content.res.Resources.NotFoundException ex) {
+ return "(unknown)";
+ }
+ } else {
+ return "(null)";
+ }
+ }
+
+ private static String visibilityToString(int vis) {
+ switch (vis) {
+ case View.INVISIBLE:
+ return "INVISIBLE";
+ case View.GONE:
+ return "GONE";
+ default:
+ return "VISIBLE";
+ }
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("NavigationBarView {");
+ final Rect r = new Rect();
+
+ pw.println(String.format(" this: " + PhoneStatusBar.viewInfo(this)
+ + " " + visibilityToString(getVisibility())));
+
+ getWindowVisibleDisplayFrame(r);
+ final boolean offscreen = r.right > mDisplay.getRawWidth()
+ || r.bottom > mDisplay.getRawHeight();
+ pw.println(" window: "
+ + r.toShortString()
+ + " " + visibilityToString(getWindowVisibility())
+ + (offscreen ? " OFFSCREEN!" : ""));
+
+ pw.println(String.format(" mCurrentView: id=%s (%dx%d) %s",
+ getResourceName(mCurrentView.getId()),
+ mCurrentView.getWidth(), mCurrentView.getHeight(),
+ visibilityToString(mCurrentView.getVisibility())));
+
+ pw.println(String.format(" disabled=0x%08x vertical=%s hidden=%s low=%s menu=%s",
+ mDisabledFlags,
+ mVertical ? "true" : "false",
+ mHidden ? "true" : "false",
+ mLowProfile ? "true" : "false",
+ mShowMenu ? "true" : "false"));
+
+ final View back = getBackButton();
+ final View home = getHomeButton();
+ final View recent = getRecentsButton();
+ final View menu = getMenuButton();
+
+ pw.println(" back: "
+ + PhoneStatusBar.viewInfo(back)
+ + " " + visibilityToString(back.getVisibility())
+ );
+ pw.println(" home: "
+ + PhoneStatusBar.viewInfo(home)
+ + " " + visibilityToString(home.getVisibility())
+ );
+ pw.println(" rcnt: "
+ + PhoneStatusBar.viewInfo(recent)
+ + " " + visibilityToString(recent.getVisibility())
+ );
+ pw.println(" menu: "
+ + PhoneStatusBar.viewInfo(menu)
+ + " " + visibilityToString(menu.getVisibility())
+ );
+ pw.println(" }");
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index f0093d3..c69a145 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1735,9 +1735,9 @@ public class PhoneStatusBar extends StatusBar {
return anim;
}
- public String viewInfo(View v) {
- return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
- + " " + v.getWidth() + "x" + v.getHeight() + ")";
+ public static String viewInfo(View v) {
+ return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
+ + ") " + v.getWidth() + "x" + v.getHeight() + "]";
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -1768,6 +1768,13 @@ public class PhoneStatusBar extends StatusBar {
+ " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
}
+ pw.print(" mNavigationBarView=");
+ if (mNavigationBarView == null) {
+ pw.println("null");
+ } else {
+ mNavigationBarView.dump(fd, pw, args);
+ }
+
if (DUMPTRUCK) {
synchronized (mNotificationData) {
int N = mNotificationData.size();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java
index 7fbf734..2d951c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java
@@ -49,6 +49,10 @@ public class CompatModeButton extends ImageView {
public void refresh() {
int mode = mAM.getFrontActivityScreenCompatMode();
+ if (mode == ActivityManager.COMPAT_MODE_UNKNOWN) {
+ // If in an unknown state, don't change.
+ return;
+ }
final boolean vis = (mode != ActivityManager.COMPAT_MODE_NEVER
&& mode != ActivityManager.COMPAT_MODE_ALWAYS);
if (DEBUG) Slog.d(TAG, "compat mode is " + mode + "; icon will " + (vis ? "show" : "hide"));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 55a5b0a..135a04c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -898,7 +898,7 @@ public class NetworkController extends BroadcastReceiver {
combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
mContentDescriptionCombinedSignal = mContentDescriptionDataType;
}
-
+
if (mWifiConnected) {
if (mWifiSsid == null) {
label = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
@@ -932,19 +932,23 @@ public class NetworkController extends BroadcastReceiver {
mContentDescriptionCombinedSignal = mContext.getString(
R.string.accessibility_bluetooth_tether);
}
-
+
if (mAirplaneMode &&
(mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
// Only display the flight-mode icon if not in "emergency calls only" mode.
- label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
- mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal
- = mContext.getString(R.string.accessibility_airplane_mode);
-
+
// look again; your radios are now airplanes
+ mContentDescriptionPhoneSignal = mContext.getString(
+ R.string.accessibility_airplane_mode);
mPhoneSignalIconId = mDataSignalIconId = R.drawable.stat_sys_signal_flightmode;
mDataTypeIconId = 0;
- combinedSignalIconId = mDataSignalIconId;
+ // combined values from connected wifi take precedence over airplane mode
+ if (!mWifiConnected) {
+ label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+ mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
+ combinedSignalIconId = mDataSignalIconId;
+ }
}
else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected) {
// pretty much totally disconnected
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 01406bc..757ce0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -534,6 +534,7 @@ public class TabletStatusBar extends StatusBar implements
mCompatModeButton = (CompatModeButton) sb.findViewById(R.id.compatModeButton);
mCompatModeButton.setOnClickListener(mOnClickListener);
+ mCompatModeButton.setVisibility(View.GONE);
// for redirecting errant bar taps to the IME
mFakeSpaceBar = sb.findViewById(R.id.fake_space_bar);
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index f040e87..8052c80 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -121,8 +121,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
R.string.global_action_silent_mode_off_status) {
void willCreate() {
- mEnabledIconResId = (Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.VIBRATE_IN_SILENT, 1) == 1)
+ mEnabledIconResId =
+ mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE
? R.drawable.ic_audio_ring_notif_vibrate
: R.drawable.ic_audio_vol_mute;
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index fd9e095..f6bf213 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -40,7 +40,6 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.BatteryManager;
-import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -69,8 +68,10 @@ import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
+import android.view.IApplicationToken;
import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputDevice;
@@ -163,9 +164,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
- // Should screen savers use their own timeout, or the SCREEN_OFF_TIMEOUT?
- static final boolean SEPARATE_TIMEOUT_FOR_SCREEN_SAVER = false;
-
static final int LONG_PRESS_POWER_NOTHING = 0;
static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
static final int LONG_PRESS_POWER_SHUT_OFF = 2;
@@ -230,7 +228,30 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Useful scan codes.
private static final int SW_LID = 0x00;
private static final int BTN_MOUSE = 0x110;
-
+
+ /* Table of Application Launch keys. Maps from key codes to intent categories.
+ *
+ * These are special keys that are used to launch particular kinds of applications,
+ * such as a web browser. HID defines nearly a hundred of them in the Consumer (0x0C)
+ * usage page. We don't support quite that many yet...
+ */
+ static SparseArray<String> sApplicationLaunchKeyCategories;
+ static {
+ sApplicationLaunchKeyCategories = new SparseArray<String>();
+ sApplicationLaunchKeyCategories.append(
+ KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER);
+ sApplicationLaunchKeyCategories.append(
+ KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL);
+ sApplicationLaunchKeyCategories.append(
+ KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS);
+ sApplicationLaunchKeyCategories.append(
+ KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR);
+ sApplicationLaunchKeyCategories.append(
+ KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC);
+ sApplicationLaunchKeyCategories.append(
+ KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
+ }
+
/**
* Lock protecting internal state. Must not call out into window
* manager with lock held. (This lock will be acquired in places
@@ -319,6 +340,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// The last window we were told about in focusChanged.
WindowState mFocusedWindow;
+ IApplicationToken mFocusedApp;
private final InputHandler mPointerLocationInputHandler = new BaseInputHandler() {
@Override
@@ -398,12 +420,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mLockScreenTimeout;
boolean mLockScreenTimerActive;
- // visual screen saver support
- int mScreenSaverTimeout = 0;
- boolean mScreenSaverEnabledByUser = false;
- boolean mScreenSaverMayRun = true; // false if a wakelock is held
- boolean mPluggedIn;
-
// Behavior of ENDCALL Button. (See Settings.System.END_BUTTON_BEHAVIOR.)
int mEndcallBehavior;
@@ -466,12 +482,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
resolver.registerContentObserver(Settings.System.getUriFor(
"fancy_rotation_anim"), false, this);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.SCREENSAVER_ENABLED), false, this);
- if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) {
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- "screensaver_timeout"), false, this);
- } // otherwise SCREEN_OFF_TIMEOUT will do nicely
updateSettings();
}
@@ -779,14 +789,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Intent.EXTRA_DOCK_STATE_UNDOCKED);
}
- // watch the plug to know whether to trigger the screen saver
- filter = new IntentFilter();
- filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- intent = context.registerReceiver(mPowerReceiver, filter);
- if (intent != null) {
- mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
- }
-
mVibrator = new Vibrator();
mLongPressVibePattern = getLongIntArray(mContext.getResources(),
com.android.internal.R.array.config_longPressVibePattern);
@@ -935,23 +937,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHasSoftInput = hasSoftInput;
updateRotation = true;
}
-
- mScreenSaverEnabledByUser = 0 != Settings.Secure.getInt(resolver,
- Settings.Secure.SCREENSAVER_ENABLED, 1);
-
- if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) {
- mScreenSaverTimeout = Settings.Secure.getInt(resolver,
- "screensaver_timeout", 0);
- } else {
- mScreenSaverTimeout = Settings.System.getInt(resolver,
- Settings.System.SCREEN_OFF_TIMEOUT, 0);
- if (mScreenSaverTimeout > 0) {
- // We actually want to activate the screensaver just before the
- // power manager's screen timeout
- mScreenSaverTimeout -= 5000;
- }
- }
- updateScreenSaverTimeoutLocked();
}
if (updateRotation) {
updateRotation(true);
@@ -1649,6 +1634,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ // Handle application launch keys.
+ if (down && repeatCount == 0) {
+ String category = sApplicationLaunchKeyCategories.get(keyCode);
+ if (category != null) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(category);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException ex) {
+ Slog.w(TAG, "Dropping application launch key because "
+ + "the activity to which it is registered was not found: "
+ + "keyCode=" + keyCode + ", category=" + category, ex);
+ }
+ }
+ }
+
return 0;
}
@@ -2986,15 +2988,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
};
- BroadcastReceiver mPowerReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
- mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
- if (localLOGV) Log.v(TAG, "BATTERY_CHANGED: " + intent + " plugged=" + mPluggedIn);
- }
- }
- };
-
/** {@inheritDoc} */
public void screenTurnedOff(int why) {
EventLog.writeEvent(70000, 0);
@@ -3006,7 +2999,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
synchronized (mLock) {
updateOrientationListenerLp();
updateLockScreenTimeout();
- updateScreenSaverTimeoutLocked();
}
}
@@ -3053,7 +3045,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mScreenOnEarly = true;
updateOrientationListenerLp();
updateLockScreenTimeout();
- updateScreenSaverTimeoutLocked();
}
}
@@ -3448,75 +3439,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
}
}
-
- synchronized (mLock) {
- // Only posts messages; holds no additional locks.
- updateScreenSaverTimeoutLocked();
- }
- }
-
- Runnable mScreenSaverActivator = new Runnable() {
- public void run() {
- if (!(mScreenSaverMayRun && mScreenOnEarly)) {
- Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?");
- return;
- }
- if (!mPluggedIn) {
- if (localLOGV) Log.v(TAG, "mScreenSaverActivator: not running screen saver when not plugged in");
- return;
- }
-
- if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland");
-
- try {
- String component = Settings.Secure.getString(
- mContext.getContentResolver(), Settings.Secure.SCREENSAVER_COMPONENT);
- if (component == null) {
- component = mContext.getResources().getString(R.string.config_defaultDreamComponent);
- }
- if (component != null) {
- // dismiss the notification shade, recents, etc.
- mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
-
- ComponentName cn = ComponentName.unflattenFromString(component);
- Intent intent = new Intent(Intent.ACTION_MAIN)
- .setComponent(cn)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_NO_USER_ACTION
- | Intent.FLAG_FROM_BACKGROUND
- | Intent.FLAG_ACTIVITY_NO_HISTORY
- );
- mContext.startActivity(intent);
- } else {
- Log.e(TAG, "Couldn't start screen saver: none selected");
- }
- } catch (android.content.ActivityNotFoundException exc) {
- // no screensaver? give up
- Log.e(TAG, "Couldn't start screen saver: none installed");
- }
- }
- };
-
- // Must call while holding mLock
- private void updateScreenSaverTimeoutLocked() {
- if (mScreenSaverActivator == null) return;
-
- mHandler.removeCallbacks(mScreenSaverActivator);
- if (mScreenSaverEnabledByUser && mScreenSaverMayRun && mScreenOnEarly && mScreenSaverTimeout > 0) {
- if (localLOGV)
- Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now");
- mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout);
- } else {
- if (localLOGV) {
- if (!mScreenSaverEnabledByUser || mScreenSaverTimeout == 0)
- Log.v(TAG, "screen saver disabled by user");
- else if (!mScreenOnEarly)
- Log.v(TAG, "screen saver disabled while screen off");
- else
- Log.v(TAG, "screen saver disabled by wakelock");
- }
- }
}
Runnable mScreenLockTimeout = new Runnable() {
@@ -3722,11 +3644,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
public void screenOnStartedLw() {
- // The window manager has just grabbed a wake lock. This is our cue to disable the screen
- // saver.
- synchronized (mLock) {
- mScreenSaverMayRun = false;
- }
}
public void screenOnStoppedLw() {
@@ -3735,13 +3652,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
long curTime = SystemClock.uptimeMillis();
mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
}
-
- synchronized (mLock) {
- // even if the keyguard is up, now that all the wakelocks have been released, we
- // should re-enable the screen saver
- mScreenSaverMayRun = true;
- updateScreenSaverTimeoutLocked();
- }
}
}
@@ -3762,11 +3672,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int diff = visibility ^ mLastSystemUiFlags;
final boolean needsMenu = (mFocusedWindow.getAttrs().flags
& WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
- if (diff == 0 && mLastFocusNeedsMenu == needsMenu) {
+ if (diff == 0 && mLastFocusNeedsMenu == needsMenu
+ && mFocusedApp == mFocusedWindow.getAppToken()) {
return 0;
}
mLastSystemUiFlags = visibility;
mLastFocusNeedsMenu = needsMenu;
+ mFocusedApp = mFocusedWindow.getAppToken();
mHandler.post(new Runnable() {
public void run() {
if (mStatusBarService == null) {
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
index d34087f..16eeb7b 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -163,7 +163,6 @@ public class DeviceStorageMonitorService extends Binder {
} catch (IllegalArgumentException e) {
// ignore; report -1
}
- mCacheFileStats.restat(CACHE_PATH);
EventLog.writeEvent(EventLogTags.FREE_STORAGE_LEFT,
mFreeMem, mFreeSystem, mFreeCache);
}
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 5408436..4dad209 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -50,12 +50,12 @@ option java_package com.android.server
# NotificationManagerService.java
# ---------------------------
# when a NotificationManager.notify is called
-2750 notification_enqueue (pkg|3),(id|1|5),(notification|3)
+2750 notification_enqueue (pkg|3),(id|1|5),(tag|3),(notification|3)
# when someone tries to cancel a notification, the notification manager sometimes
# calls this with flags too
-2751 notification_cancel (pkg|3),(id|1|5),(required_flags|1)
+2751 notification_cancel (pkg|3),(id|1|5),(tag|3),(required_flags|1),(forbidden_flags|1)
# when someone tries to cancel all of the notifications for a particular package
-2752 notification_cancel_all (pkg|3),(required_flags|1)
+2752 notification_cancel_all (pkg|3),(required_flags|1),(forbidden_flags|1)
# ---------------------------
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 7d1d976..5039294 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -707,7 +707,8 @@ public class NotificationManagerService extends INotificationManager.Stub
// behalf of the download manager without affecting other apps.
if (!pkg.equals("com.android.providers.downloads")
|| Log.isLoggable("DownloadManager", Log.VERBOSE)) {
- EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, notification.toString());
+ EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag,
+ notification.toString());
}
if (pkg == null || notification == null) {
@@ -944,7 +945,8 @@ public class NotificationManagerService extends INotificationManager.Stub
*/
private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
int mustNotHaveFlags, boolean sendDelete) {
- EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags);
+ EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, tag,
+ mustHaveFlags, mustNotHaveFlags);
synchronized (mNotificationList) {
int index = indexOfNotificationLocked(pkg, tag, id);
@@ -972,7 +974,8 @@ public class NotificationManagerService extends INotificationManager.Stub
*/
boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags,
int mustNotHaveFlags, boolean doit) {
- EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags);
+ EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags,
+ mustNotHaveFlags);
synchronized (mNotificationList) {
final int N = mNotificationList.size();
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 6b23b33..2a0d2a0 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -1689,6 +1689,11 @@ public class PowerManagerService extends IPowerManager.Stub
// before showing it to the user. We want the light off
// until it is ready to be shown to the user, not it using
// whatever the last value it had.
+ if (DEBUG_SCREEN_ON) {
+ Slog.i(TAG, "Forcing brightness 0: mPowerState=0x"
+ + Integer.toHexString(mPowerState)
+ + " mSkippedScreenOn=" + mSkippedScreenOn);
+ }
mScreenBrightness.forceValueLocked(Power.BRIGHTNESS_OFF);
}
}
@@ -2038,12 +2043,14 @@ public class PowerManagerService extends IPowerManager.Stub
} finally {
Binder.restoreCallingIdentity(identity);
}
- mScreenBrightness.setTargetLocked(brightness, steps,
- INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
- if (DEBUG_SCREEN_ON) {
- RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
- Slog.i(TAG, "Setting screen brightness: " + brightness, e);
+ if (!mSkippedScreenOn) {
+ mScreenBrightness.setTargetLocked(brightness, steps,
+ INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
+ if (DEBUG_SCREEN_ON) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Slog.i(TAG, "Setting screen brightness: " + brightness, e);
+ }
}
}
@@ -2086,6 +2093,11 @@ public class PowerManagerService extends IPowerManager.Stub
? LightsService.BRIGHTNESS_MODE_SENSOR
: LightsService.BRIGHTNESS_MODE_USER);
if ((mask & SCREEN_BRIGHT_BIT) != 0) {
+ if (DEBUG_SCREEN_ON) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Slog.i(TAG, "Set LCD brightness: " + value, e);
+ }
mLcdLight.setBrightness(value, brightnessMode);
}
if ((mask & BUTTON_BRIGHT_BIT) != 0) {
@@ -2137,7 +2149,7 @@ public class PowerManagerService extends IPowerManager.Stub
delta = (targetValue -
(nominalCurrentValue >= 0 ? nominalCurrentValue : curValue))
/ stepsToTarget;
- if (mSpew) {
+ if (mSpew || DEBUG_SCREEN_ON) {
String noticeMe = nominalCurrentValue == curValue ? "" : " ******************";
Slog.i(TAG, "setTargetLocked mask=" + mask + " curValue=" + curValue
+ " target=" + target + " targetValue=" + targetValue + " delta=" + delta
@@ -2527,8 +2539,10 @@ public class PowerManagerService extends IPowerManager.Stub
}
if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) {
- mScreenBrightness.setTargetLocked(lcdValue, AUTOBRIGHTNESS_ANIM_STEPS,
- INITIAL_SCREEN_BRIGHTNESS, (int)mScreenBrightness.curValue);
+ if (!mSkippedScreenOn) {
+ mScreenBrightness.setTargetLocked(lcdValue, AUTOBRIGHTNESS_ANIM_STEPS,
+ INITIAL_SCREEN_BRIGHTNESS, (int)mScreenBrightness.curValue);
+ }
}
if (mButtonBrightnessOverride < 0) {
mButtonLight.setBrightness(buttonValue);
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index d04b440..8384ebc 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -392,9 +392,16 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
Slog.d(TAG, "FinishSpellCheckerService");
}
synchronized(mSpellCheckerMap) {
+ final ArrayList<SpellCheckerBindGroup> removeList =
+ new ArrayList<SpellCheckerBindGroup>();
for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) {
if (group == null) continue;
- group.removeListener(listener);
+ // Use removeList to avoid modifying mSpellCheckerBindGroups in this loop.
+ removeList.add(group);
+ }
+ final int removeSize = removeList.size();
+ for (int i = 0; i < removeSize; ++i) {
+ removeList.get(i).removeListener(listener);
}
}
}
@@ -669,6 +676,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
+ // cleanLocked may remove elements from mSpellCheckerBindGroups
private void cleanLocked() {
if (DBG) {
Slog.d(TAG, "cleanLocked");
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index e6392d7..c7fbc00 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -65,7 +65,7 @@ class UiModeManagerService extends IUiModeManager.Stub {
// Enable launching of applications when entering the dock.
private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
- private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = false;
+ private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
private static final int MSG_UPDATE_TWILIGHT = 0;
private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 7fa404e..4925a4e 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -476,6 +476,13 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
ParcelFileDescriptor updateWallpaperBitmapLocked(String name) {
if (name == null) name = "";
try {
+ if (!WALLPAPER_DIR.exists()) {
+ WALLPAPER_DIR.mkdir();
+ FileUtils.setPermissions(
+ WALLPAPER_DIR.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ }
ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
MODE_CREATE|MODE_READ_WRITE);
mName = name;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index fd528cc..b70ed96 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -115,8 +115,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
- private final SparseArray<IAccessibilityInteractionConnection> mWindowIdToInteractionConnectionMap =
- new SparseArray<IAccessibilityInteractionConnection>();
+ private final SparseArray<AccessibilityConnectionWrapper> mWindowIdToInteractionConnectionWrapperMap =
+ new SparseArray<AccessibilityConnectionWrapper>();
private final SparseArray<IBinder> mWindowIdToWindowTokenMap = new SparseArray<IBinder>();
@@ -439,16 +439,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
final IWindow addedWindowToken = windowToken;
final IAccessibilityInteractionConnection addedConnection = connection;
final int windowId = sNextWindowId++;
- addedConnection.asBinder().linkToDeath(new DeathRecipient() {
- public void binderDied() {
- synchronized (mLock) {
- addedConnection.asBinder().unlinkToDeath(this, 0);
- removeAccessibilityInteractionConnection(addedWindowToken);
- }
- }
- }, 0);
+ AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(windowId,
+ connection);
+ wrapper.linkToDeath();
mWindowIdToWindowTokenMap.put(windowId, addedWindowToken.asBinder());
- mWindowIdToInteractionConnectionMap.put(windowId, connection);
+ mWindowIdToInteractionConnectionWrapperMap.put(windowId, wrapper);
if (DEBUG) {
Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId);
}
@@ -462,18 +457,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
for (int i = 0; i < count; i++) {
if (mWindowIdToWindowTokenMap.valueAt(i) == windowToken.asBinder()) {
final int windowId = mWindowIdToWindowTokenMap.keyAt(i);
- mWindowIdToWindowTokenMap.remove(windowId);
- mWindowIdToInteractionConnectionMap.remove(windowId);
- if (DEBUG) {
- Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
- }
+ AccessibilityConnectionWrapper wrapper =
+ mWindowIdToInteractionConnectionWrapperMap.get(windowId);
+ wrapper.unlinkToDeath();
+ removeAccessibilityInteractionConnectionLocked(windowId);
return;
}
}
}
}
- public IAccessibilityServiceConnection registerEventListener(IEventListener listener) {
+ public void registerEventListener(IEventListener listener) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
FUNCTION_REGISTER_EVENT_LISTENER);
ComponentName componentName = new ComponentName("foo.bar",
@@ -501,7 +495,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
Service service = new Service(componentName, accessibilityServiceInfo, true);
service.onServiceConnected(componentName, listener.asBinder());
- return service;
+ }
+
+ /**
+ * Removes an AccessibilityInteractionConnection.
+ *
+ * @param windowId The id of the window to which the connection is targeted.
+ */
+ private void removeAccessibilityInteractionConnectionLocked(int windowId) {
+ mWindowIdToWindowTokenMap.remove(windowId);
+ mWindowIdToInteractionConnectionWrapperMap.remove(windowId);
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
+ }
}
/**
@@ -594,6 +600,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
private void notifyEventListenerLocked(Service service, int eventType) {
IEventListener listener = service.mServiceInterface;
+
+ // If the service died/was disabled while the message for dispatching
+ // the accessibility event was propagating the listener may be null.
+ if (listener == null) {
+ return;
+ }
+
AccessibilityEvent event = service.mPendingEvents.get(eventType);
// Check for null here because there is a concurrent scenario in which this
@@ -618,7 +631,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
service.mPendingEvents.remove(eventType);
try {
if (mSecurityPolicy.canRetrieveWindowContent(service)) {
- event.setConnection(service);
+ event.setConnectionId(service.mId);
} else {
event.setSource(null);
}
@@ -666,6 +679,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mComponentNameToServiceMap.remove(service.mComponentName);
mHandler.removeMessages(service.mId);
service.unlinkToOwnDeath();
+ service.dispose();
updateInputFilterLocked();
return removed;
}
@@ -895,6 +909,33 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
sendStateToClientsLocked();
}
+ private class AccessibilityConnectionWrapper implements DeathRecipient {
+ private final int mWindowId;
+ private final IAccessibilityInteractionConnection mConnection;
+
+ public AccessibilityConnectionWrapper(int windowId,
+ IAccessibilityInteractionConnection connection) {
+ mWindowId = windowId;
+ mConnection = connection;
+ }
+
+ public void linkToDeath() throws RemoteException {
+ mConnection.asBinder().linkToDeath(this, 0);
+ }
+
+ public void unlinkToDeath() {
+ mConnection.asBinder().unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ unlinkToDeath();
+ synchronized (mLock) {
+ removeAccessibilityInteractionConnectionLocked(mWindowId);
+ }
+ }
+ }
+
/**
* This class represents an accessibility service. It stores all per service
* data required for the service management, provides API for starting/stopping the
@@ -997,7 +1038,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (!mIsAutomation) {
mContext.unbindService(this);
}
- mService = null;
return true;
}
return false;
@@ -1021,7 +1061,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mService = service;
mServiceInterface = IEventListener.Stub.asInterface(service);
try {
- mServiceInterface.setConnection(this);
+ mServiceInterface.setConnection(this, mId);
synchronized (mLock) {
tryAddServiceLocked(this);
}
@@ -1123,14 +1163,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (!permissionGranted) {
return 0;
} else {
- connection = mWindowIdToInteractionConnectionMap.get(accessibilityWindowId);
- if (connection == null) {
+ AccessibilityConnectionWrapper wrapper =
+ mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId);
+ if (wrapper == null) {
if (DEBUG) {
Slog.e(LOG_TAG, "No interaction connection to window: "
+ accessibilityWindowId);
}
return 0;
}
+ connection = wrapper.mConnection;
}
}
final int interrogatingPid = Binder.getCallingPid();
@@ -1159,14 +1201,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (!permissionGranted) {
return false;
} else {
- connection = mWindowIdToInteractionConnectionMap.get(accessibilityWindowId);
- if (connection == null) {
+ AccessibilityConnectionWrapper wrapper =
+ mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId);
+ if (wrapper == null) {
if (DEBUG) {
Slog.e(LOG_TAG, "No interaction connection to window: "
+ accessibilityWindowId);
}
return false;
}
+ connection = wrapper.mConnection;
}
}
final int interrogatingPid = Binder.getCallingPid();
@@ -1197,9 +1241,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mService.unlinkToDeath(this, 0);
}
+ public void dispose() {
+ try {
+ // Clear the proxy in the other process so this
+ // IAccessibilityServiceConnection can be garbage collected.
+ mServiceInterface.setConnection(null, mId);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ mService = null;
+ mServiceInterface = null;
+ }
+
public void binderDied() {
synchronized (mLock) {
- mService.unlinkToDeath(this, 0);
+ unlinkToOwnDeath();
tryRemoveServiceLocked(this);
// We no longer have an automation service, so restore
// the state based on values in the settings database.
@@ -1214,7 +1270,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (DEBUG) {
Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
}
- return mWindowIdToInteractionConnectionMap.get(windowId);
+ AccessibilityConnectionWrapper wrapper =
+ mWindowIdToInteractionConnectionWrapperMap.get(windowId);
+ return (wrapper != null) ? wrapper.mConnection : null;
}
private float getCompatibilityScale(int windowId) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8023477..a4d321d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -129,7 +129,6 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -415,7 +414,12 @@ public final class ActivityManagerService extends ActivityManagerNative
* is in a different process from the one they are currently in.
*/
ProcessRecord mPreviousProcess;
-
+
+ /**
+ * The time at which the previous process was last visible.
+ */
+ long mPreviousProcessVisibleTime;
+
/**
* Packages that the user has asked to have run in screen size
* compatibility mode instead of filling the screen.
@@ -1222,6 +1226,23 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override public void run() {
StringBuilder dropBuilder = new StringBuilder(1024);
StringBuilder logBuilder = new StringBuilder(1024);
+ StringWriter oomSw = new StringWriter();
+ PrintWriter oomPw = new PrintWriter(oomSw);
+ StringWriter catSw = new StringWriter();
+ PrintWriter catPw = new PrintWriter(catSw);
+ String[] emptyArgs = new String[] { };
+ StringBuilder tag = new StringBuilder(128);
+ StringBuilder stack = new StringBuilder(128);
+ tag.append("Low on memory -- ");
+ dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw,
+ tag, stack);
+ dropBuilder.append(stack);
+ dropBuilder.append('\n');
+ dropBuilder.append('\n');
+ String oomString = oomSw.toString();
+ dropBuilder.append(oomString);
+ dropBuilder.append('\n');
+ logBuilder.append(oomString);
try {
java.lang.Process proc = Runtime.getRuntime().exec(new String[] {
"procrank", });
@@ -1244,27 +1265,15 @@ public final class ActivityManagerService extends ActivityManagerNative
converter.close();
} catch (IOException e) {
}
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- StringWriter catSw = new StringWriter();
- PrintWriter catPw = new PrintWriter(catSw);
- String[] emptyArgs = new String[] { };
- StringBuilder tag = new StringBuilder(128);
synchronized (ActivityManagerService.this) {
+ catPw.println();
dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
catPw.println();
dumpServicesLocked(null, catPw, emptyArgs, 0, false, false, null);
catPw.println();
dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
- catPw.println();
}
- tag.append("Low on memory -- ");
- dumpApplicationMemoryUsage(null, pw, " ", emptyArgs, true, catPw, tag);
- String memUsage = sw.toString();
- dropBuilder.append('\n');
- dropBuilder.append(memUsage);
dropBuilder.append(catSw.toString());
- logBuilder.append(memUsage);
addErrorToDropBox("lowmem", null, "system_server", null,
null, tag.toString(), dropBuilder.toString(), null, null);
Slog.i(TAG, logBuilder.toString());
@@ -1420,7 +1429,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args,
- false, null, null);
+ false, null, null, null);
}
}
@@ -2716,6 +2725,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (!r.finishing) {
Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
+ EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
+ System.identityHashCode(r),
+ r.task.taskId, r.shortComponentName,
+ "proc died without state saved");
}
r.makeFinishing();
mMainStack.mHistory.remove(i);
@@ -8353,6 +8366,12 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println();
pw.println(" mHomeProcess: " + mHomeProcess);
pw.println(" mPreviousProcess: " + mPreviousProcess);
+ if (dumpAll) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append(" mPreviousProcessVisibleTime: ");
+ TimeUtils.formatDuration(mPreviousProcessVisibleTime, sb);
+ pw.println(sb);
+ }
if (mHeavyWeightProcess != null) {
pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess);
}
@@ -9416,7 +9435,7 @@ public final class ActivityManagerService extends ActivityManagerNative
} else if (r.setAdj >= ProcessList.SERVICE_ADJ) {
oomAdj = buildOomTag("svc ", null, r.setAdj, ProcessList.SERVICE_ADJ);
} else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) {
- oomAdj = buildOomTag("bckup", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
+ oomAdj = buildOomTag("bkup ", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
} else if (r.setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
oomAdj = buildOomTag("hvy ", null, r.setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
} else if (r.setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -9645,7 +9664,8 @@ public final class ActivityManagerService extends ActivityManagerNative
1*1024*1024, 2*1024*1024, 5*1024*1024, 10*1024*1024, 20*1024*1024
};
- static final void appendMemBucket(StringBuilder out, long memKB, String label) {
+ static final void appendMemBucket(StringBuilder out, long memKB, String label,
+ boolean stackLike) {
int start = label.lastIndexOf('.');
if (start >= 0) start++;
else start = 0;
@@ -9654,13 +9674,13 @@ public final class ActivityManagerService extends ActivityManagerNative
if (DUMP_MEM_BUCKETS[i] >= memKB) {
long bucket = DUMP_MEM_BUCKETS[i]/1024;
out.append(bucket);
- out.append("MB ");
+ out.append(stackLike ? "MB." : "MB ");
out.append(label, start, end);
return;
}
}
out.append(memKB/1024);
- out.append("MB ");
+ out.append(stackLike ? "MB." : "MB ");
out.append(label, start, end);
}
@@ -9679,7 +9699,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args, boolean brief,
- PrintWriter categoryPw, StringBuilder outTag) {
+ PrintWriter categoryPw, StringBuilder outTag, StringBuilder outStack) {
boolean dumpAll = false;
boolean oomOnly = false;
@@ -9816,8 +9836,14 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- if (outTag != null) {
- appendMemBucket(outTag, totalPss, "total");
+ if (outTag != null || outStack != null) {
+ if (outTag != null) {
+ appendMemBucket(outTag, totalPss, "total", false);
+ }
+ if (outStack != null) {
+ appendMemBucket(outStack, totalPss, "total", true);
+ }
+ boolean firstLine = true;
for (int i=0; i<oomMems.size(); i++) {
MemItem miCat = oomMems.get(i);
if (miCat.subitems == null || miCat.subitems.size() < 1) {
@@ -9826,13 +9852,47 @@ public final class ActivityManagerService extends ActivityManagerNative
if (miCat.id < ProcessList.SERVICE_ADJ
|| miCat.id == ProcessList.HOME_APP_ADJ
|| miCat.id == ProcessList.PREVIOUS_APP_ADJ) {
- outTag.append(" / ");
+ if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
+ outTag.append(" / ");
+ }
+ if (outStack != null) {
+ if (miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
+ if (firstLine) {
+ outStack.append(":");
+ firstLine = false;
+ }
+ outStack.append("\n\t at ");
+ } else {
+ outStack.append("$");
+ }
+ }
for (int j=0; j<miCat.subitems.size(); j++) {
MemItem mi = miCat.subitems.get(j);
if (j > 0) {
- outTag.append(" ");
+ if (outTag != null) {
+ outTag.append(" ");
+ }
+ if (outStack != null) {
+ outStack.append("$");
+ }
+ }
+ if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
+ appendMemBucket(outTag, mi.pss, mi.shortLabel, false);
+ }
+ if (outStack != null) {
+ appendMemBucket(outStack, mi.pss, mi.shortLabel, true);
}
- appendMemBucket(outTag, mi.pss, mi.shortLabel);
+ }
+ if (outStack != null && miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
+ outStack.append("(");
+ for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
+ if (DUMP_MEM_OOM_ADJ[k] == miCat.id) {
+ outStack.append(DUMP_MEM_OOM_LABEL[k]);
+ outStack.append(":");
+ outStack.append(DUMP_MEM_OOM_ADJ[k]);
+ }
+ }
+ outStack.append(")");
}
}
}
@@ -13551,6 +13611,7 @@ public final class ActivityManagerService extends ActivityManagerNative
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "stopping";
}
+ app.hidden = false;
app.foregroundActivities = true;
}
}
@@ -14199,7 +14260,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (app.curAdj != app.setAdj) {
if (Process.setOomAdj(app.pid, app.curAdj)) {
- if (true || DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
TAG, "Set " + app.pid + " " + app.processName +
" adj " + app.curAdj + ": " + app.adjType);
app.setAdj = app.curAdj;
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 951a946..c819114 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -80,6 +80,7 @@ final class ActivityRecord {
ThumbnailHolder thumbHolder; // where our thumbnails should go.
long launchTime; // when we starting launching this activity
long startTime; // last time this activity was started
+ long lastVisibleTime; // last time this activity became visible
long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
Configuration configuration; // configuration activity was last running in
CompatibilityInfo compat;// last used compatibility mode
@@ -188,6 +189,10 @@ final class ActivityRecord {
TimeUtils.formatDuration(launchTime, pw); pw.print(" startTime=");
TimeUtils.formatDuration(startTime, pw); pw.println("");
}
+ if (lastVisibleTime != 0) {
+ pw.print(prefix); pw.print("lastVisibleTime=");
+ TimeUtils.formatDuration(lastVisibleTime, pw); pw.println("");
+ }
if (waitingVisible || nowVisible) {
pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible);
pw.print(" nowVisible="); pw.println(nowVisible);
@@ -632,6 +637,7 @@ final class ActivityRecord {
ActivityManagerService.TAG, "windowsVisible(): " + this);
if (!nowVisible) {
nowVisible = true;
+ lastVisibleTime = SystemClock.uptimeMillis();
if (!idle) {
// Instead of doing the full stop routine here, let's just
// hide any activities we now can, and let them stop when
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index c7ce3c3..b5edc0a 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -949,6 +949,22 @@ final class ActivityStack {
if (r.configDestroy) {
destroyActivityLocked(r, true, false, "stop-config");
resumeTopActivityLocked(null);
+ } else {
+ // Now that this process has stopped, we may want to consider
+ // it to be the previous app to try to keep around in case
+ // the user wants to return to it.
+ ProcessRecord fgApp = null;
+ if (mResumedActivity != null) {
+ fgApp = mResumedActivity.app;
+ } else if (mPausingActivity != null) {
+ fgApp = mPausingActivity.app;
+ }
+ if (r.app != null && fgApp != null && r.app != fgApp
+ && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
+ && r.app != mService.mHomeProcess) {
+ mService.mPreviousProcess = r.app;
+ mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
+ }
}
}
}
@@ -1363,14 +1379,6 @@ final class ActivityStack {
+ ", nowVisible=" + next.nowVisible);
}
}
-
- if (!prev.finishing && prev.app != null && prev.app != next.app
- && prev.app != mService.mHomeProcess) {
- // We are switching to a new activity that is in a different
- // process than the previous one. Note the previous process,
- // so we can try to keep it around.
- mService.mPreviousProcess = prev.app;
- }
}
// Launching this app's activity, make sure the app is no longer
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index ee62a56..77575f2 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -151,18 +151,22 @@ final class Session extends IWindowSession.Stub
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags,
- boolean insetsPending, Rect outFrame, Rect outContentInsets,
+ int flags, Rect outFrame, Rect outContentInsets,
Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
int res = mService.relayoutWindow(this, window, seq, attrs,
- requestedWidth, requestedHeight, viewFlags, insetsPending,
+ requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface);
if (false) Slog.d(WindowManagerService.TAG, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
return res;
}
+ public void performDeferredDestroy(IWindow window) {
+ mService.performDeferredDestroyWindow(this, window);
+ }
+
public boolean outOfMemory(IWindow window) {
return mService.outOfMemoryWindow(this, window);
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index ebb13d5..f5c2de9 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -429,6 +429,18 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mSystemBooted = false;
boolean mForceDisplayEnabled = false;
boolean mShowingBootMessages = false;
+
+ // This protects the following display size properties, so that
+ // getDisplaySize() doesn't need to acquire the global lock. This is
+ // needed because the window manager sometimes needs to use ActivityThread
+ // while it has its global state locked (for example to load animation
+ // resources), but the ActivityThread also needs get the current display
+ // size sometimes when it has its package lock held.
+ //
+ // These will only be modified with both mWindowMap and mDisplaySizeLock
+ // held (in that order) so the window manager doesn't need to acquire this
+ // lock when needing these values in its normal operation.
+ final Object mDisplaySizeLock = new Object();
int mInitialDisplayWidth = 0;
int mInitialDisplayHeight = 0;
int mBaseDisplayWidth = 0;
@@ -437,6 +449,7 @@ public class WindowManagerService extends IWindowManager.Stub
int mCurDisplayHeight = 0;
int mAppDisplayWidth = 0;
int mAppDisplayHeight = 0;
+
int mRotation = 0;
int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
boolean mAltOrientation = false;
@@ -2499,12 +2512,13 @@ public class WindowManagerService extends IWindowManager.Stub
public int relayoutWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int requestedWidth,
- int requestedHeight, int viewVisibility, boolean insetsPending,
+ int requestedHeight, int viewVisibility, int flags,
Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
Configuration outConfig, Surface outSurface) {
boolean displayed = false;
boolean inTouchMode;
boolean configChanged;
+ boolean surfaceChanged = false;
// if they don't have this permission, mask out the status bar bits
int systemUiVisibility = 0;
@@ -2534,6 +2548,9 @@ public class WindowManagerService extends IWindowManager.Stub
mPolicy.adjustWindowParamsLw(attrs);
}
+ win.mSurfaceDestroyDeferred =
+ (flags&WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY) != 0;
+
int attrChanges = 0;
int flagChanges = 0;
if (attrs != null) {
@@ -2630,8 +2647,12 @@ public class WindowManagerService extends IWindowManager.Stub
// To change the format, we need to re-build the surface.
win.destroySurfaceLocked();
displayed = true;
+ surfaceChanged = true;
}
try {
+ if (win.mSurface == null) {
+ surfaceChanged = true;
+ }
Surface surface = win.createSurfaceLocked();
if (surface != null) {
outSurface.copyFrom(surface);
@@ -2683,6 +2704,7 @@ public class WindowManagerService extends IWindowManager.Stub
// If we are not currently running the exit animation, we
// need to see about starting one.
if (!win.mExiting || win.mSurfacePendingDestroy) {
+ surfaceChanged = true;
// Try starting an animation; if there isn't one, we
// can destroy the surface right away.
int transit = WindowManagerPolicy.TRANSIT_EXIT;
@@ -2715,10 +2737,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (win.mSurface == null || (win.getAttrs().flags
& WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING) == 0
|| win.mSurfacePendingDestroy) {
- // We are being called from a local process, which
+ // We could be called from a local process, which
// means outSurface holds its current surface. Ensure the
- // surface object is cleared, but we don't want it actually
- // destroyed at this point.
+ // surface object is cleared, but we don't necessarily want
+ // it actually destroyed at this point.
win.mSurfacePendingDestroy = false;
outSurface.release();
if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
@@ -2760,7 +2782,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
mLayoutNeeded = true;
- win.mGivenInsetsPending = insetsPending;
+ win.mGivenInsetsPending = (flags&WindowManagerImpl.RELAYOUT_INSETS_PENDING) != 0;
if (assignLayers) {
assignLayersLocked();
}
@@ -2797,8 +2819,25 @@ public class WindowManagerService extends IWindowManager.Stub
Binder.restoreCallingIdentity(origId);
- return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0)
- | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0);
+ return (inTouchMode ? WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE : 0)
+ | (displayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0)
+ | (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0);
+ }
+
+ public void performDeferredDestroyWindow(Session session, IWindow client) {
+ long origId = Binder.clearCallingIdentity();
+
+ try {
+ synchronized(mWindowMap) {
+ WindowState win = windowForClientLocked(session, client, false);
+ if (win == null) {
+ return;
+ }
+ win.destroyDeferredSurfaceLocked();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
public boolean outOfMemoryWindow(Session session, IWindow client) {
@@ -3738,7 +3777,7 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- // If this is a translucent or wallpaper window, then don't
+ // If this is a translucent window, then don't
// show a starting window -- the current effect (a full-screen
// opaque starting window that fades away to the real contents
// when it is ready) does not work for this.
@@ -3755,7 +3794,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
- return;
+ if (mWallpaperTarget == null) {
+ // If this theme is requesting a wallpaper, and the wallpaper
+ // is not curently visible, then this effectively serves as
+ // an opaque window and our starting window transition animation
+ // can still work. We just need to make sure the starting window
+ // is also showing the wallpaper.
+ windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+ } else {
+ return;
+ }
}
}
@@ -5971,25 +6019,27 @@ public class WindowManagerService extends IWindowManager.Stub
final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
- if (mAltOrientation) {
- mCurDisplayWidth = realdw;
- mCurDisplayHeight = realdh;
- if (realdw > realdh) {
- // Turn landscape into portrait.
- int maxw = (int)(realdh/1.3f);
- if (maxw < realdw) {
- mCurDisplayWidth = maxw;
+ synchronized(mDisplaySizeLock) {
+ if (mAltOrientation) {
+ mCurDisplayWidth = realdw;
+ mCurDisplayHeight = realdh;
+ if (realdw > realdh) {
+ // Turn landscape into portrait.
+ int maxw = (int)(realdh/1.3f);
+ if (maxw < realdw) {
+ mCurDisplayWidth = maxw;
+ }
+ } else {
+ // Turn portrait into landscape.
+ int maxh = (int)(realdw/1.3f);
+ if (maxh < realdh) {
+ mCurDisplayHeight = maxh;
+ }
}
} else {
- // Turn portrait into landscape.
- int maxh = (int)(realdw/1.3f);
- if (maxh < realdh) {
- mCurDisplayHeight = maxh;
- }
+ mCurDisplayWidth = realdw;
+ mCurDisplayHeight = realdh;
}
- } else {
- mCurDisplayWidth = realdw;
- mCurDisplayHeight = realdh;
}
final int dw = mCurDisplayWidth;
@@ -6008,8 +6058,12 @@ public class WindowManagerService extends IWindowManager.Stub
// Update application display metrics.
final DisplayMetrics dm = mDisplayMetrics;
- mAppDisplayWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
- mAppDisplayHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
+ final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
+ final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
+ synchronized(mDisplaySizeLock) {
+ mAppDisplayWidth = appWidth;
+ mAppDisplayHeight = appHeight;
+ }
if (false) {
Slog.i(TAG, "Set app display size: " + mAppDisplayWidth
+ " x " + mAppDisplayHeight);
@@ -6379,18 +6433,20 @@ public class WindowManagerService extends IWindowManager.Stub
}
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mDisplay = wm.getDefaultDisplay();
- mInitialDisplayWidth = mDisplay.getRawWidth();
- mInitialDisplayHeight = mDisplay.getRawHeight();
- int rot = mDisplay.getRotation();
- if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
- // If the screen is currently rotated, we need to swap the
- // initial width and height to get the true natural values.
- int tmp = mInitialDisplayWidth;
- mInitialDisplayWidth = mInitialDisplayHeight;
- mInitialDisplayHeight = tmp;
- }
- mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth;
- mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight;
+ synchronized(mDisplaySizeLock) {
+ mInitialDisplayWidth = mDisplay.getRawWidth();
+ mInitialDisplayHeight = mDisplay.getRawHeight();
+ int rot = mDisplay.getRotation();
+ if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
+ // If the screen is currently rotated, we need to swap the
+ // initial width and height to get the true natural values.
+ int tmp = mInitialDisplayWidth;
+ mInitialDisplayWidth = mInitialDisplayHeight;
+ mInitialDisplayHeight = tmp;
+ }
+ mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth;
+ mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight;
+ }
mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
mDisplay.getRawWidth(), mDisplay.getRawHeight(),
mDisplay.getRawExternalWidth(), mDisplay.getRawExternalHeight());
@@ -6928,28 +6984,28 @@ public class WindowManagerService extends IWindowManager.Stub
}
public void getDisplaySize(Point size) {
- synchronized(mWindowMap) {
+ synchronized(mDisplaySizeLock) {
size.x = mAppDisplayWidth;
size.y = mAppDisplayHeight;
}
}
public void getRealDisplaySize(Point size) {
- synchronized(mWindowMap) {
+ synchronized(mDisplaySizeLock) {
size.x = mCurDisplayWidth;
size.y = mCurDisplayHeight;
}
}
public void getInitialDisplaySize(Point size) {
- synchronized(mWindowMap) {
+ synchronized(mDisplaySizeLock) {
size.x = mInitialDisplayWidth;
size.y = mInitialDisplayHeight;
}
}
public int getMaximumSizeDimension() {
- synchronized(mWindowMap) {
+ synchronized(mDisplaySizeLock) {
// Do this based on the raw screen size, until we are smarter.
return mBaseDisplayWidth > mBaseDisplayHeight
? mBaseDisplayWidth : mBaseDisplayHeight;
@@ -7042,8 +7098,10 @@ public class WindowManagerService extends IWindowManager.Stub
private void setForcedDisplaySizeLocked(int width, int height) {
Slog.i(TAG, "Using new display size: " + width + "x" + height);
- mBaseDisplayWidth = width;
- mBaseDisplayHeight = height;
+ synchronized(mDisplaySizeLock) {
+ mBaseDisplayWidth = width;
+ mBaseDisplayHeight = height;
+ }
mPolicy.setInitialDisplaySize(mBaseDisplayWidth, mBaseDisplayHeight);
mLayoutNeeded = true;
@@ -7659,7 +7717,8 @@ public class WindowManagerService extends IWindowManager.Stub
// a detached wallpaper animation.
if (nowAnimating) {
if (w.mAnimation != null) {
- if (w.mAnimation.getDetachWallpaper()) {
+ if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
+ && w.mAnimation.getDetachWallpaper()) {
windowDetachedWallpaper = w;
}
if (w.mAnimation.getBackgroundColor() != 0) {
@@ -7679,7 +7738,8 @@ public class WindowManagerService extends IWindowManager.Stub
// displayed behind it.
if (w.mAppToken != null && w.mAppToken.animation != null
&& w.mAppToken.animating) {
- if (w.mAppToken.animation.getDetachWallpaper()) {
+ if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
+ && w.mAppToken.animation.getDetachWallpaper()) {
windowDetachedWallpaper = w;
}
if (w.mAppToken.animation.getBackgroundColor() != 0) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 23ec2d9..aa7bf2d 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -85,6 +85,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
boolean mPolicyVisibilityAfterAnim = true;
boolean mAppFreezing;
Surface mSurface;
+ Surface mPendingDestroySurface;
boolean mReportDestroySurface;
boolean mSurfacePendingDestroy;
boolean mAttachedHidden; // is our parent window hidden?
@@ -121,7 +122,13 @@ final class WindowState implements WindowManagerPolicy.WindowState {
* we must tell them application to resize (and thus redraw itself).
*/
boolean mSurfaceResized;
-
+
+ /**
+ * Set if the client has asked that the destroy of its surface be delayed
+ * until it explicitly says it is okay.
+ */
+ boolean mSurfaceDestroyDeferred;
+
/**
* Insets that determine the actually visible area. These are in the application's
* coordinate space (without compatibility scale applied).
@@ -764,15 +771,32 @@ final class WindowState implements WindowManagerPolicy.WindowState {
Slog.w(WindowManagerService.TAG, "Window " + this + " destroying surface "
+ mSurface + ", session " + mSession, e);
}
- if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
- RuntimeException e = null;
- if (!WindowManagerService.HIDE_STACK_CRAWLS) {
- e = new RuntimeException();
- e.fillInStackTrace();
+ if (mSurfaceDestroyDeferred) {
+ if (mSurface != null && mPendingDestroySurface != mSurface) {
+ if (mPendingDestroySurface != null) {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ RuntimeException e = null;
+ if (!WindowManagerService.HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ WindowManagerService.logSurface(this, "DESTROY PENDING", e);
+ }
+ mPendingDestroySurface.destroy();
+ }
+ mPendingDestroySurface = mSurface;
}
- WindowManagerService.logSurface(this, "DESTROY", e);
+ } else {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ RuntimeException e = null;
+ if (!WindowManagerService.HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ WindowManagerService.logSurface(this, "DESTROY", e);
+ }
+ mSurface.destroy();
}
- mSurface.destroy();
} catch (RuntimeException e) {
Slog.w(WindowManagerService.TAG, "Exception thrown when destroying Window " + this
+ " surface " + mSurface + " session " + mSession
@@ -784,6 +808,28 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
}
+ void destroyDeferredSurfaceLocked() {
+ try {
+ if (mPendingDestroySurface != null) {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ RuntimeException e = null;
+ if (!WindowManagerService.HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ mService.logSurface(this, "DESTROY PENDING", e);
+ }
+ mPendingDestroySurface.destroy();
+ }
+ } catch (RuntimeException e) {
+ Slog.w(WindowManagerService.TAG, "Exception thrown when destroying Window "
+ + this + " surface " + mPendingDestroySurface
+ + " session " + mSession + ": " + e.toString());
+ }
+ mSurfaceDestroyDeferred = false;
+ mPendingDestroySurface = null;
+ }
+
boolean finishDrawingLocked() {
if (mDrawPending) {
if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) Slog.v(
@@ -977,6 +1023,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mAnimation.cancel();
mAnimation = null;
}
+ if (mService.mWindowDetachedWallpaper == this) {
+ mService.mWindowDetachedWallpaper = null;
+ }
mAnimLayer = mLayer;
if (mIsImWindow) {
mAnimLayer += mService.mInputMethodAnimLayerAdjustment;
@@ -1415,6 +1464,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(WindowManagerService.TAG, "Removing " + this + " from " + mAttachedWindow);
mAttachedWindow.mChildWindows.remove(this);
}
+ destroyDeferredSurfaceLocked();
destroySurfaceLocked();
mSession.windowRemovedLocked();
try {
@@ -1612,6 +1662,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
pw.print(") "); pw.print(mSurfaceW);
pw.print(" x "); pw.println(mSurfaceH);
}
+ if (mPendingDestroySurface != null) {
+ pw.print(prefix); pw.print("mPendingDestroySurface=");
+ pw.println(mPendingDestroySurface);
+ }
if (dumpAll) {
pw.print(prefix); pw.print("mToken="); pw.println(mToken);
pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
@@ -1640,6 +1694,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
if (!mRelayoutCalled) {
pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled);
}
+ if (mSurfaceResized || mSurfaceDestroyDeferred) {
+ pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized);
+ pw.print(" mSurfaceDestroyDeferred="); pw.println(mSurfaceDestroyDeferred);
+ }
if (mXOffset != 0 || mYOffset != 0) {
pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
pw.print(" y="); pw.println(mYOffset);
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 61a8358..f63c0c1 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -28,6 +28,7 @@ ifeq ($(TARGET_BOARD_PLATFORM), omap4)
endif
ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
+ LOCAL_CFLAGS += -DREFRESH_RATE=56
endif
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1b00e93..f38e948 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -65,6 +65,8 @@
#define AID_GRAPHICS 1003
#endif
+#define EGL_VERSION_HW_ANDROID 0x3143
+
#define DISPLAY_COUNT 1
namespace android {
@@ -1527,7 +1529,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
* Dump the layers in the purgatory
*/
- const size_t purgatorySize = mLayerPurgatory.size();
+ const size_t purgatorySize = mLayerPurgatory.size();
snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
result.append(buffer);
for (size_t i=0 ; i<purgatorySize ; i++) {
@@ -1548,6 +1550,12 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
extensions.getRenderer(),
extensions.getVersion());
result.append(buffer);
+
+ snprintf(buffer, SIZE, "EGL : %s\n",
+ eglQueryString(graphicPlane(0).getEGLDisplay(),
+ EGL_VERSION_HW_ANDROID));
+ result.append(buffer);
+
snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
result.append(buffer);
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 4390ca1..5020e00 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -28,7 +28,7 @@ namespace android {
SurfaceTextureLayer::SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer)
- : SurfaceTexture(tex), mLayer(layer) {
+ : SurfaceTexture(tex, true, GL_TEXTURE_EXTERNAL_OES, false), mLayer(layer) {
}
SurfaceTextureLayer::~SurfaceTextureLayer() {
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 636646e..4619899 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -699,8 +699,10 @@ public abstract class DataConnection extends StateMachine {
break;
case EVENT_DISCONNECT:
- if (DBG) log("DcDefaultState: msg.what=EVENT_DISCONNECT");
- notifyDisconnectCompleted((DisconnectParams) msg.obj);
+ if (DBG) {
+ log("DcDefaultState deferring msg.what=EVENT_DISCONNECT" + mRefCount);
+ }
+ deferMessage(msg);
break;
case EVENT_RIL_CONNECTED:
@@ -807,6 +809,12 @@ public abstract class DataConnection extends StateMachine {
retVal = HANDLED;
break;
+ case EVENT_DISCONNECT:
+ if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT");
+ notifyDisconnectCompleted((DisconnectParams)msg.obj);
+ retVal = HANDLED;
+ break;
+
default:
if (VDBG) {
log("DcInactiveState nothandled msg.what=0x" +
@@ -831,13 +839,6 @@ public abstract class DataConnection extends StateMachine {
ConnectionParams cp;
switch (msg.what) {
- case EVENT_DISCONNECT:
- if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT"
- + mRefCount);
- deferMessage(msg);
- retVal = HANDLED;
- break;
-
case EVENT_CONNECT:
if (DBG) log("DcActivatingState deferring msg.what=EVENT_CONNECT refCount = "
+ mRefCount);
diff --git a/tests/FrameworkPerf/res/layout/main.xml b/tests/FrameworkPerf/res/layout/main.xml
index 7812648..e00ad92 100644
--- a/tests/FrameworkPerf/res/layout/main.xml
+++ b/tests/FrameworkPerf/res/layout/main.xml
@@ -66,7 +66,24 @@
>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="Limit by: "
+ />
+ <Spinner android:id="@+id/limitspinner"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:drawSelectorOnTop="true"
+ />
+ </LinearLayout>
+
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginTop="10dp"
+ >
+ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Test time (ms): "
+ android:id="@+id/limitlabel"
/>
<EditText android:id="@+id/testtime"
android:layout_width="match_parent"
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java
index 8ee5978..30a968f 100644
--- a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java
@@ -50,6 +50,8 @@ public class FrameworkPerfActivity extends Activity
Spinner mFgSpinner;
Spinner mBgSpinner;
+ Spinner mLimitSpinner;
+ TextView mLimitLabel;
TextView mTestTime;
Button mStartButton;
Button mStopButton;
@@ -58,10 +60,12 @@ public class FrameworkPerfActivity extends Activity
PowerManager.WakeLock mPartialWakeLock;
long mMaxRunTime = 5000;
+ boolean mLimitIsIterations;
boolean mStarted;
final String[] mAvailOpLabels;
final String[] mAvailOpDescriptions;
+ final String[] mLimitLabels = { "Time", "Iterations" };
int mFgTestIndex = -1;
int mBgTestIndex = -1;
@@ -169,8 +173,15 @@ public class FrameworkPerfActivity extends Activity
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mBgSpinner.setAdapter(adapter);
mBgSpinner.setOnItemSelectedListener(this);
+ mLimitSpinner = (Spinner) findViewById(R.id.limitspinner);
+ adapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_spinner_item, mLimitLabels);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mLimitSpinner.setAdapter(adapter);
+ mLimitSpinner.setOnItemSelectedListener(this);
mTestTime = (TextView)findViewById(R.id.testtime);
+ mLimitLabel = (TextView)findViewById(R.id.limitlabel);
mStartButton = (Button)findViewById(R.id.start);
mStartButton.setOnClickListener(new View.OnClickListener() {
@@ -196,16 +207,23 @@ public class FrameworkPerfActivity extends Activity
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- if (parent == mFgSpinner || parent == mBgSpinner) {
+ if (parent == mFgSpinner || parent == mBgSpinner || parent == mLimitSpinner) {
TestService.Op op = TestService.mAvailOps[position];
if (parent == mFgSpinner) {
mFgTestIndex = position;
mFgTest = op;
((TextView)findViewById(R.id.fgtext)).setText(mAvailOpDescriptions[position]);
- } else {
+ } else if (parent == mBgSpinner) {
mBgTestIndex = position;
mBgTest = op;
((TextView)findViewById(R.id.bgtext)).setText(mAvailOpDescriptions[position]);
+ } else if (parent == mLimitSpinner) {
+ mLimitIsIterations = (position != 0);
+ if (mLimitIsIterations) {
+ mLimitLabel.setText("Iterations: ");
+ } else {
+ mLimitLabel.setText("Test time (ms): ");
+ }
}
}
}
@@ -234,7 +252,11 @@ public class FrameworkPerfActivity extends Activity
return;
}
TestArgs args = new TestArgs();
- args.maxTime = mMaxRunTime;
+ if (mLimitIsIterations) {
+ args.maxOps = mMaxRunTime;
+ } else {
+ args.maxTime = mMaxRunTime;
+ }
if (mFgTestIndex == 0 && mBgTestIndex == 0) {
args.combOp = mCurOpIndex;
} else if (mFgTestIndex != 0 && mBgTestIndex != 0) {
@@ -376,6 +398,7 @@ public class FrameworkPerfActivity extends Activity
mTestTime.setEnabled(false);
mFgSpinner.setEnabled(false);
mBgSpinner.setEnabled(false);
+ mLimitSpinner.setEnabled(false);
updateWakeLock();
startService(new Intent(this, SchedulerService.class));
mCurOpIndex = 0;
@@ -397,6 +420,7 @@ public class FrameworkPerfActivity extends Activity
mTestTime.setEnabled(true);
mFgSpinner.setEnabled(true);
mBgSpinner.setEnabled(true);
+ mLimitSpinner.setEnabled(true);
updateWakeLock();
stopService(new Intent(this, SchedulerService.class));
synchronized (mResults) {
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/TestArgs.java b/tests/FrameworkPerf/src/com/android/frameworkperf/TestArgs.java
index f2f7c56..2fe38aa 100644
--- a/tests/FrameworkPerf/src/com/android/frameworkperf/TestArgs.java
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/TestArgs.java
@@ -21,6 +21,7 @@ import android.os.Parcelable;
public class TestArgs implements Parcelable {
long maxTime;
+ long maxOps = -1;
int combOp = -1;
int fgOp = -1;
int bgOp = -1;
@@ -30,6 +31,7 @@ public class TestArgs implements Parcelable {
public TestArgs(Parcel source) {
maxTime = source.readLong();
+ maxOps = source.readLong();
combOp = source.readInt();
fgOp = source.readInt();
bgOp = source.readInt();
@@ -43,6 +45,7 @@ public class TestArgs implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(maxTime);
+ dest.writeLong(maxOps);
dest.writeInt(combOp);
dest.writeInt(fgOp);
dest.writeInt(bgOp);
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java b/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java
index 8cf1ac2..a8c43e9 100644
--- a/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java
@@ -224,6 +224,7 @@ public class TestService extends Service {
public class TestRunner {
Handler mHandler;
long mMaxRunTime;
+ long mMaxOps;
Op mForegroundOp;
Op mBackgroundOp;
Runnable mDoneCallback;
@@ -277,6 +278,7 @@ public class TestService extends Service {
public void run(Handler handler, TestArgs args, Runnable doneCallback) {
mHandler = handler;
mMaxRunTime = args.maxTime;
+ mMaxOps = args.maxOps;
if (args.combOp >= 0) {
mForegroundOp = mOpPairs[args.combOp];
mBackgroundOp = mOpPairs[args.combOp+1];
@@ -352,9 +354,18 @@ public class TestService extends Service {
if (!mBackgroundRunning && !mForegroundRunning) {
return false;
}
- long now = SystemClock.uptimeMillis();
- if (now > (mStartTime+mMaxRunTime)) {
- return false;
+ if (mMaxOps > 0) {
+ // iteration-limited case
+ if (mForegroundOps >= mMaxOps) {
+ return false;
+ }
+ mForegroundOps++;
+ } else {
+ // time-limited case
+ long now = SystemClock.uptimeMillis();
+ if (now > (mStartTime+mMaxRunTime)) {
+ return false;
+ }
}
return true;
}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
index b1cef15..10802b4 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
@@ -110,9 +110,9 @@ public class ProfiledWebView extends WebView {
* been redrawn.
*/
@Override
- protected void pageSwapCallback() {
+ protected void pageSwapCallback(boolean startAnim) {
mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
- super.pageSwapCallback();
+ super.pageSwapCallback(startAnim);
Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis
+ "millis");
mIsTesting = true;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 1d97e15..a640a91 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -79,12 +79,16 @@ public final class BridgeWindowSession implements IWindowSession {
}
public int relayout(IWindow arg0, int seq, LayoutParams arg1, int arg2, int arg3, int arg4,
- boolean arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
+ int arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
throws RemoteException {
// pass for now.
return 0;
}
+ public void performDeferredDestroy(IWindow window) {
+ // pass for now.
+ }
+
public boolean outOfMemory(IWindow window) throws RemoteException {
return false;
}