Merge "Add test for bug #4970944"
diff --git a/api/current.txt b/api/current.txt
index 2923805..f3dda785 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14392,7 +14392,7 @@
method public static final void sendSignal(int, int);
method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
- method public static final boolean supportsProcesses();
+ method public static final deprecated boolean supportsProcesses();
field public static final int BLUETOOTH_GID = 2000; // 0x7d0
field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
field public static final int LAST_APPLICATION_UID = 99999; // 0x1869f
@@ -16007,6 +16007,7 @@
protected static abstract interface ContactsContract.GroupsColumns {
field public static final java.lang.String AUTO_ADD = "auto_add";
+ field public static final java.lang.String DATA_SET = "data_set";
field public static final java.lang.String DELETED = "deleted";
field public static final java.lang.String FAVORITES = "favorites";
field public static final java.lang.String GROUP_IS_READ_ONLY = "group_is_read_only";
@@ -16134,6 +16135,7 @@
protected static abstract interface ContactsContract.RawContactsColumns {
field public static final java.lang.String AGGREGATION_MODE = "aggregation_mode";
field public static final java.lang.String CONTACT_ID = "contact_id";
+ field public static final java.lang.String DATA_SET = "data_set";
field public static final java.lang.String DELETED = "deleted";
field public static final java.lang.String RAW_CONTACT_IS_READ_ONLY = "raw_contact_is_read_only";
field public static final java.lang.String RAW_CONTACT_IS_USER_PROFILE = "raw_contact_is_user_profile";
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 479b70a..3fb1736 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -157,6 +157,11 @@
String value = nextArgRequired();
intent.putExtra(key, Integer.valueOf(value));
hasIntentInfo = true;
+ } else if (opt.equals("--eu")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, Uri.parse(value));
+ hasIntentInfo = true;
} else if (opt.equals("--eia")) {
String key = nextArgRequired();
String value = nextArgRequired();
@@ -1119,6 +1124,7 @@
" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
" [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
" [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
+ " [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
" [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
" [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
" [-n <COMPONENT>] [-f <FLAGS>]\n" +
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 152a7cb..f2be29f 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -82,35 +82,27 @@
virtual void onStarted()
{
sp<ProcessState> proc = ProcessState::self();
- if (proc->supportsProcesses()) {
- LOGV("App process: starting thread pool.\n");
- proc->startThreadPool();
- }
+ LOGV("App process: starting thread pool.\n");
+ proc->startThreadPool();
AndroidRuntime* ar = AndroidRuntime::getRuntime();
ar->callMain(mClassName, mClass, mArgC, mArgV);
- if (ProcessState::self()->supportsProcesses()) {
- IPCThreadState::self()->stopProcess();
- }
+ IPCThreadState::self()->stopProcess();
}
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
- if (proc->supportsProcesses()) {
- LOGV("App process: starting thread pool.\n");
- proc->startThreadPool();
- }
+ LOGV("App process: starting thread pool.\n");
+ proc->startThreadPool();
}
virtual void onExit(int code)
{
if (mClassName == NULL) {
// if zygote
- if (ProcessState::self()->supportsProcesses()) {
- IPCThreadState::self()->stopProcess();
- }
+ IPCThreadState::self()->stopProcess();
}
AndroidRuntime::onExit(code);
diff --git a/cmds/runtime/Android.mk b/cmds/runtime/Android.mk
deleted file mode 100644
index 6a72d10..0000000
--- a/cmds/runtime/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-ifeq ($(TARGET_SIMULATOR),true)
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- ServiceManager.cpp \
- SignalHandler.cpp \
- main_runtime.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libutils \
- libbinder \
- libandroid_runtime \
- libcutils \
- libui \
- libsystem_server \
- libhardware_legacy
-
-LOCAL_C_INCLUDES := \
- $(JNI_H_INCLUDE)
-
-ifeq ($(TARGET_OS),linux)
- LOCAL_CFLAGS += -DXP_UNIX
-endif
-
-LOCAL_MODULE:= runtime
-
-include $(BUILD_EXECUTABLE)
-endif
diff --git a/cmds/runtime/MODULE_LICENSE_APACHE2 b/cmds/runtime/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/cmds/runtime/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/cmds/runtime/NOTICE b/cmds/runtime/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/cmds/runtime/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/cmds/runtime/ServiceManager.cpp b/cmds/runtime/ServiceManager.cpp
deleted file mode 100644
index b2bef07..0000000
--- a/cmds/runtime/ServiceManager.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-
-#define LOG_TAG "ServiceManager"
-
-#include "ServiceManager.h"
-#include "SignalHandler.h"
-
-#include <utils/Debug.h>
-#include <utils/Log.h>
-#include <binder/Parcel.h>
-#include <utils/String8.h>
-#include <binder/ProcessState.h>
-
-#include <private/utils/Static.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-
-namespace android {
-
-BServiceManager::BServiceManager()
-{
-}
-
-sp<IBinder> BServiceManager::getService(const String16& name) const
-{
- AutoMutex _l(mLock);
- ssize_t i = mServices.indexOfKey(name);
- LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i);
- if (i >= 0) return mServices.valueAt(i);
- return NULL;
-}
-
-sp<IBinder> BServiceManager::checkService(const String16& name) const
-{
- AutoMutex _l(mLock);
- ssize_t i = mServices.indexOfKey(name);
- LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i);
- if (i >= 0) return mServices.valueAt(i);
- return NULL;
-}
-
-status_t BServiceManager::addService(const String16& name, const sp<IBinder>& service)
-{
- AutoMutex _l(mLock);
- LOGI("ServiceManager: addService(%s, %p)\n", String8(name).string(), service.get());
- const ssize_t res = mServices.add(name, service);
- if (res >= NO_ERROR) {
- mChanged.broadcast();
- return NO_ERROR;
- }
- return res;
-}
-
-Vector<String16> BServiceManager::listServices()
-{
- Vector<String16> res;
-
- AutoMutex _l(mLock);
- const size_t N = mServices.size();
- for (size_t i=0; i<N; i++) {
- res.add(mServices.keyAt(i));
- }
-
- return res;
-}
-
-}; // namespace android
diff --git a/cmds/runtime/ServiceManager.h b/cmds/runtime/ServiceManager.h
deleted file mode 100644
index 090ca6d..0000000
--- a/cmds/runtime/ServiceManager.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-#ifndef ANDROID_SERVICE_MANAGER_H
-#define ANDROID_SERVICE_MANAGER_H
-
-#include <binder/IServiceManager.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class BServiceManager : public BnServiceManager
-{
-public:
- BServiceManager();
-
- virtual sp<IBinder> getService( const String16& name) const;
- virtual sp<IBinder> checkService( const String16& name) const;
- virtual status_t addService( const String16& name,
- const sp<IBinder>& service);
- virtual Vector<String16> listServices();
-
-
-private:
- mutable Mutex mLock;
- mutable Condition mChanged;
- sp<IPermissionController> mPermissionController;
- KeyedVector<String16, sp<IBinder> > mServices;
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_SERVICE_MANAGER_H
diff --git a/cmds/runtime/SignalHandler.cpp b/cmds/runtime/SignalHandler.cpp
deleted file mode 100644
index cccaabf..0000000
--- a/cmds/runtime/SignalHandler.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-
-#define LOG_TAG "SignalHandler"
-
-#include "SignalHandler.h"
-
-#include <utils/Atomic.h>
-#include <utils/Debug.h>
-#include <utils/Log.h>
-
-#include <errno.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-namespace android {
-
-class SignalHandler::ProcessThread : public Thread
-{
-public:
- ProcessThread(SignalHandler& sh)
- : Thread(false)
- , mOwner(sh)
- {
- }
-
- virtual bool threadLoop()
- {
- char buffer[32];
- read(mOwner.mAvailMsg[0], buffer, sizeof(buffer));
-
- LOGV("Signal command processing thread woke up!");
-
- if (mOwner.mLostCommands) {
- LOGE("Lost %d signals!", mOwner.mLostCommands);
- mOwner.mLostCommands = 0;
- }
-
- int cur;
- while ((cur=mOwner.mCommandBottom) != mOwner.mCommandTop) {
- if (mOwner.mCommands[cur].filled == 0) {
- LOGV("Command at %d is not yet filled", cur);
- break;
- }
-
- LOGV("Processing command at %d, top is %d",
- cur, mOwner.mCommandTop);
- processCommand(mOwner.mCommands[cur]);
- mOwner.mCommands[cur].filled = 0;
-
- int next = mOwner.mCommandBottom+1;
- if (next >= COMMAND_QUEUE_SIZE) {
- next = 0;
- }
-
- mOwner.mCommandBottom = next;
- }
-
- return true;
- }
-
- void processCommand(const CommandEntry& entry)
- {
- switch (entry.signum) {
- case SIGCHLD: {
- mOwner.mLock.lock();
- ssize_t i = mOwner.mChildHandlers.indexOfKey(entry.info.si_pid);
- ChildHandler ch;
- if (i >= 0) {
- ch = mOwner.mChildHandlers.valueAt(i);
- mOwner.mChildHandlers.removeItemsAt(i);
- }
- mOwner.mLock.unlock();
-
- LOGD("SIGCHLD: pid=%d, handle index=%d", entry.info.si_pid, i);
-
- if (i >= 0) {
- int res = waitpid(entry.info.si_pid, NULL, WNOHANG);
- LOGW_IF(res == 0,
- "Received SIGCHLD, but pid %d is not yet stopped",
- entry.info.si_pid);
- if (ch.handler) {
- ch.handler(entry.info.si_pid, ch.userData);
- }
- } else {
- LOGW("Unhandled SIGCHLD for pid %d", entry.info.si_pid);
- }
- } break;
- }
- }
-
- SignalHandler& mOwner;
-};
-
-
-Mutex SignalHandler::mInstanceLock;
-SignalHandler* SignalHandler::mInstance = NULL;
-
-status_t SignalHandler::setChildHandler(pid_t childPid,
- int tag,
- child_callback_t handler,
- void* userData)
-{
- SignalHandler* const self = getInstance();
-
- self->mLock.lock();
-
- // First make sure this child hasn't already exited.
- pid_t res = waitpid(childPid, NULL, WNOHANG);
- if (res != 0) {
- if (res < 0) {
- LOGW("setChildHandler waitpid of %d failed: %d (%s)",
- childPid, res, strerror(errno));
- } else {
- LOGW("setChildHandler waitpid of %d said %d already dead",
- childPid, res);
- }
-
- // Some kind of error... just handle the exit now.
- self->mLock.unlock();
-
- if (handler) {
- handler(childPid, userData);
- }
-
- // Return an error code -- 0 means it already exited.
- return (status_t)res;
- }
-
- ChildHandler entry;
- entry.childPid = childPid;
- entry.tag = tag;
- entry.handler = handler;
- entry.userData = userData;
-
- // Note: this replaces an existing entry for this pid, if there already
- // is one. This is the required behavior.
- LOGD("setChildHandler adding pid %d, tag %d, handler %p, data %p",
- childPid, tag, handler, userData);
- self->mChildHandlers.add(childPid, entry);
-
- self->mLock.unlock();
-
- return NO_ERROR;
-}
-
-void SignalHandler::killAllChildren(int tag)
-{
- SignalHandler* const self = getInstance();
-
- AutoMutex _l (self->mLock);
- const size_t N = self->mChildHandlers.size();
- for (size_t i=0; i<N; i++) {
- const ChildHandler& ch(self->mChildHandlers.valueAt(i));
- if (tag == 0 || ch.tag == tag) {
- const pid_t pid = ch.childPid;
- LOGI("Killing child %d (tag %d)\n", pid, ch.tag);
- kill(pid, SIGKILL);
- }
- }
-}
-
-SignalHandler::SignalHandler()
- : mCommandTop(0)
- , mCommandBottom(0)
- , mLostCommands(0)
-{
- memset(mCommands, 0, sizeof(mCommands));
-
- int res = pipe(mAvailMsg);
- LOGE_IF(res != 0, "Unable to create signal handler pipe: %s", strerror(errno));
-
- mProcessThread = new ProcessThread(*this);
- mProcessThread->run("SignalHandler", PRIORITY_HIGHEST);
-
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_sigaction = sigAction;
- sa.sa_flags = SA_NOCLDSTOP|SA_SIGINFO;
- sigaction(SIGCHLD, &sa, NULL);
-}
-
-SignalHandler::~SignalHandler()
-{
-}
-
-SignalHandler* SignalHandler::getInstance()
-{
- AutoMutex _l(mInstanceLock);
- if (mInstance == NULL) {
- mInstance = new SignalHandler();
- }
- return mInstance;
-}
-
-void SignalHandler::sigAction(int signum, siginfo_t* info, void*)
-{
- static const char wakeupMsg[1] = { 0xff };
-
- // If our signal handler is being called, then we know we have
- // already initialized the SignalHandler class and thus mInstance
- // is valid.
- SignalHandler* const self = mInstance;
-
- // XXX This is not safe!
- #if 0
- LOGV("Signal %d: signo=%d, errno=%d, code=%d, pid=%d\n",
- signum,
- info->si_signo, info->si_errno, info->si_code,
- info->si_pid);
- #endif
-
- int32_t oldTop, newTop;
-
- // Find the next command slot...
- do {
- oldTop = self->mCommandTop;
-
- newTop = oldTop + 1;
- if (newTop >= COMMAND_QUEUE_SIZE) {
- newTop = 0;
- }
-
- if (newTop == self->mCommandBottom) {
- // The buffer is filled up! Ouch!
- // XXX This is not safe!
- #if 0
- LOGE("Command buffer overflow! newTop=%d\n", newTop);
- #endif
- android_atomic_add(1, &self->mLostCommands);
- write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
- return;
- }
- } while(android_atomic_cmpxchg(oldTop, newTop, &(self->mCommandTop)));
-
- // Fill in the command data...
- self->mCommands[oldTop].signum = signum;
- self->mCommands[oldTop].info = *info;
-
- // And now make this command available.
- self->mCommands[oldTop].filled = 1;
-
- // Wake up the processing thread.
- write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
-}
-
-}; // namespace android
-
diff --git a/cmds/runtime/SignalHandler.h b/cmds/runtime/SignalHandler.h
deleted file mode 100644
index 7f4ef8e..0000000
--- a/cmds/runtime/SignalHandler.h
+++ /dev/null
@@ -1,137 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-#ifndef ANDROID_SIGNAL_HANDLER_H
-#define ANDROID_SIGNAL_HANDLER_H
-
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-
-#include <signal.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-enum {
- DEFAULT_PROCESS_TAG = 1
-};
-
-class SignalHandler
-{
-public:
- typedef void (*child_callback_t)(pid_t child, void* userData);
-
- /**
- * Set a handler for when a child process exits. By calling
- * this, a waitpid() will be done when the child exits to remove
- * it from the zombie state. You can also optionally specify a
- * handler to be called when the child exits.
- *
- * If there is already a handler for this child process, it is
- * replaced by this new handler. In this case the old handler's
- * function is not called.
- *
- * @param childPid Process ID of child to watch.
- * @param childTag User-defined tag for this child. Must be
- * greater than zero.
- * @param handler If non-NULL, this will be called when the
- * child exits. It may be called in either a
- * separate signal handling thread, or
- * immediately if the child has already exited.
- * @param userData Propageted as-is to handler.
- *
- * @return status_t NO_ERROR if all is well.
- */
- static status_t setChildHandler(pid_t childPid,
- int childTag = DEFAULT_PROCESS_TAG,
- child_callback_t handler = NULL,
- void* userData = NULL);
-
- /**
- * Kill all of the child processes for which we have a waiting
- * handler, whose tag is the given value. If tag is 0, all
- * children are killed.
- *
- * @param tag
- */
- static void killAllChildren(int tag = 0);
-
-private:
- SignalHandler();
- ~SignalHandler();
-
- static SignalHandler* getInstance();
-
- static void sigAction(int, siginfo_t*, void*);
-
- // --------------------------------------------------
- // Shared state... all of this is protected by mLock.
- // --------------------------------------------------
-
- mutable Mutex mLock;
-
- struct ChildHandler
- {
- pid_t childPid;
- int tag;
- child_callback_t handler;
- void* userData;
- };
- KeyedVector<pid_t, ChildHandler> mChildHandlers;
-
- // --------------------------------------------------
- // Commmand queue... data is inserted by the signal
- // handler using atomic ops, and retrieved by the
- // signal processing thread. Because these are touched
- // by the signal handler, no lock is used.
- // --------------------------------------------------
-
- enum {
- COMMAND_QUEUE_SIZE = 64
- };
- struct CommandEntry
- {
- int filled;
- int signum;
- siginfo_t info;
- };
-
- // The top of the queue. This is incremented atomically by the
- // signal handler before placing a command in the queue.
- volatile int32_t mCommandTop;
-
- // The bottom of the queue. Only modified by the processing
- // thread; the signal handler reads it only to determine if the
- // queue is full.
- int32_t mCommandBottom;
-
- // Incremented each time we receive a signal and don't have room
- // for it on the command queue.
- volatile int32_t mLostCommands;
-
- // The command processing thread.
- class ProcessThread;
- sp<Thread> mProcessThread;
-
- // Pipe used to tell command processing thread when new commands.
- // are available. The thread blocks on the read end, the signal
- // handler writes when it enqueues new commands.
- int mAvailMsg[2];
-
- // The commands.
- CommandEntry mCommands[COMMAND_QUEUE_SIZE];
-
- // --------------------------------------------------
- // Singleton.
- // --------------------------------------------------
-
- static Mutex mInstanceLock;
- static SignalHandler* mInstance;
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_SIGNAL_HANDLER_H
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
deleted file mode 100644
index dbff095..0000000
--- a/cmds/runtime/main_runtime.cpp
+++ /dev/null
@@ -1,515 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Main entry point for runtime.
-//
-
-#include "ServiceManager.h"
-#include "SignalHandler.h"
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <utils/Log.h>
-#include <cutils/zygote.h>
-
-#include <cutils/properties.h>
-
-#include <private/utils/Static.h>
-
-#include <surfaceflinger/ISurfaceComposer.h>
-
-#include <android_runtime/AndroidRuntime.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <linux/capability.h>
-#include <linux/ioctl.h>
-#ifdef HAVE_ANDROID_OS
-# include <linux/android_alarm.h>
-#endif
-
-#undef LOG_TAG
-#define LOG_TAG "runtime"
-
-static const char* ZYGOTE_ARGV[] = {
- "--setuid=1000",
- "--setgid=1000",
- "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
- /* CAP_SYS_TTY_CONFIG & CAP_SYS_RESOURCE & CAP_NET_BROADCAST &
- * CAP_NET_ADMIN & CAP_NET_RAW & CAP_NET_BIND_SERVICE & CAP_KILL &
- * CAP_SYS_BOOT CAP_SYS_NICE
- */
- "--capabilities=96549920,96549920",
- "--runtime-init",
- "--nice-name=system_server",
- "com.android.server.SystemServer"
-};
-
-using namespace android;
-
-extern "C" status_t system_init();
-
-enum {
- SYSTEM_PROCESS_TAG = DEFAULT_PROCESS_TAG+1
-};
-
-extern Mutex gEventQMutex;
-extern Condition gEventQCondition;
-
-namespace android {
-
-extern void set_finish_init_func(void (*func)());
-
-
-/**
- * This class is used to kill this process (runtime) when the system_server dies.
- */
-class GrimReaper : public IBinder::DeathRecipient {
-public:
- GrimReaper() { }
-
- virtual void binderDied(const wp<IBinder>& who)
- {
- LOGI("Grim Reaper killing runtime...");
- kill(getpid(), SIGKILL);
- }
-};
-
-extern void QuickTests();
-
-/*
- * Print usage info.
- */
-static void usage(const char* argv0)
-{
- fprintf(stderr,
- "Usage: runtime [-g gamma] [-l logfile] [-n] [-s]\n"
- " [-j app-component] [-v app-verb] [-d app-data]\n"
- "\n"
- "-l: File to send log messages to\n"
- "-n: Don't print to stdout/stderr\n"
- "-s: Force single-process mode\n"
- "-j: Custom home app component name\n"
- "-v: Custom home app intent verb\n"
- "-d: Custom home app intent data\n"
- );
- exit(1);
-}
-
-// Selected application to run.
-static const char* gInitialApplication = NULL;
-static const char* gInitialVerb = NULL;
-static const char* gInitialData = NULL;
-
-static void writeStringToParcel(Parcel& parcel, const char* str)
-{
- if (str) {
- parcel.writeString16(String16(str));
- } else {
- parcel.writeString16(NULL, 0);
- }
-}
-
-/*
- * Starting point for program logic.
- *
- * Returns with an exit status code (0 on success, nonzero on error).
- */
-static int run(sp<ProcessState>& proc)
-{
- // Temporary hack to call startRunning() on the activity manager.
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> am;
- while ((am = sm->getService(String16("activity"))) == NULL) {
- LOGI("Waiting for activity manager...");
- }
- Parcel data, reply;
- // XXX Need to also supply a package name for this to work again.
- // IActivityManager::getInterfaceDescriptor() is the token for invoking on this interface;
- // hardcoding it here avoids having to link with the full Activity Manager library
- data.writeInterfaceToken(String16("android.app.IActivityManager"));
- writeStringToParcel(data, NULL);
- writeStringToParcel(data, gInitialApplication);
- writeStringToParcel(data, gInitialVerb);
- writeStringToParcel(data, gInitialData);
-LOGI("run() sending FIRST_CALL_TRANSACTION to activity manager");
- am->transact(IBinder::FIRST_CALL_TRANSACTION, data, &reply);
-
- if (proc->supportsProcesses()) {
- // Now we link to the Activity Manager waiting for it to die. If it does kill ourself.
- // initd will restart this process and bring the system back up.
- sp<GrimReaper> grim = new GrimReaper();
- am->linkToDeath(grim, grim.get(), 0);
-
- // Now join the thread pool. Note this is needed so that the message enqueued in the driver
- // for the linkToDeath gets processed.
- IPCThreadState::self()->joinThreadPool();
- } else {
- // Keep this thread running forever...
- while (1) {
- usleep(100000);
- }
- }
- return 1;
-}
-
-
-}; // namespace android
-
-
-/*
- * Post-system-process initialization.
- *
- * This function continues initialization after the system process
- * has been initialized. It needs to be separate because the system
- * initialization needs to care of starting the Android runtime if it is not
- * running in its own process, which doesn't return until the runtime is
- * being shut down. So it will call back to here from inside of Dalvik,
- * to allow us to continue booting up.
- */
-static void finish_system_init(sp<ProcessState>& proc)
-{
- // If we are running multiprocess, we now need to have the
- // thread pool started here. We don't do this in boot_init()
- // because when running single process we need to start the
- // thread pool after the Android runtime has been started (so
- // the pool uses Dalvik threads).
- if (proc->supportsProcesses()) {
- proc->startThreadPool();
- }
-}
-
-
-// This function can be used to enforce security to different
-// root contexts. For now, we just give every access.
-static bool contextChecker(
- const String16& name, const sp<IBinder>& caller, void* userData)
-{
- return true;
-}
-
-/*
- * Initialization of boot services.
- *
- * This is where we perform initialization of all of our low-level
- * boot services. Most importantly, here we become the context
- * manager and use that to publish the service manager that will provide
- * access to all other services.
- */
-static void boot_init()
-{
- LOGI("Entered boot_init()!\n");
-
- sp<ProcessState> proc(ProcessState::self());
- LOGD("ProcessState: %p\n", proc.get());
- proc->becomeContextManager(contextChecker, NULL);
-
- if (proc->supportsProcesses()) {
- LOGI("Binder driver opened. Multiprocess enabled.\n");
- } else {
- LOGI("Binder driver not found. Processes not supported.\n");
- }
-
- sp<BServiceManager> sm = new BServiceManager;
- proc->setContextObject(sm);
-}
-
-/*
- * Redirect stdin/stdout/stderr to /dev/null.
- */
-static void redirectStdFds(void)
-{
- int fd = open("/dev/null", O_RDWR, 0);
- if (fd < 0) {
- LOGW("Unable to open /dev/null: %s\n", strerror(errno));
- } else {
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- close(fd);
- }
-}
-
-static int hasDir(const char* dir)
-{
- struct stat s;
- int res = stat(dir, &s);
- if (res == 0) {
- return S_ISDIR(s.st_mode);
- }
- return 0;
-}
-
-static void validateTime()
-{
-#if HAVE_ANDROID_OS
- int fd;
- int res;
- time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year
- struct timespec ts;
-
- fd = open("/dev/alarm", O_RDWR);
- if(fd < 0) {
- LOGW("Unable to open alarm driver: %s\n", strerror(errno));
- return;
- }
- res = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_RTC_WAKEUP), &ts);
- if(res < 0) {
- LOGW("Unable to read rtc, %s\n", strerror(errno));
- }
- else if(ts.tv_sec >= min_time) {
- goto done;
- }
- LOGW("Invalid time detected, %ld set to %ld\n", ts.tv_sec, min_time);
- ts.tv_sec = min_time;
- ts.tv_nsec = 0;
- res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
- if(res < 0) {
- LOGW("Unable to set rtc to %ld: %s\n", ts.tv_sec, strerror(errno));
- }
-done:
- close(fd);
-#endif
-}
-
-#ifndef HAVE_ANDROID_OS
-class QuickRuntime : public AndroidRuntime
-{
-public:
- QuickRuntime() {}
-
- virtual void onStarted()
- {
- printf("QuickRuntime: onStarted\n");
- }
-};
-#endif
-
-static status_t start_process(const char* name);
-
-static void restart_me(pid_t child, void* userData)
-{
- start_process((const char*)userData);
-}
-
-static status_t start_process(const char* name)
-{
- String8 path(name);
- Vector<const char*> args;
- String8 leaf(path.getPathLeaf());
- String8 parentDir(path.getPathDir());
- args.insertAt(leaf.string(), 0);
- args.add(parentDir.string());
- args.add(NULL);
- pid_t child = fork();
- if (child < 0) {
- status_t err = errno;
- LOGE("*** fork of child %s failed: %s", leaf.string(), strerror(err));
- return -errno;
- } else if (child == 0) {
- LOGI("Executing: %s", path.string());
- execv(path.string(), const_cast<char**>(args.array()));
- int err = errno;
- LOGE("Exec failed: %s\n", strerror(err));
- _exit(err);
- } else {
- SignalHandler::setChildHandler(child, DEFAULT_PROCESS_TAG,
- restart_me, (void*)name);
- }
- return -errno;
-}
-
-/*
- * Application entry point.
- *
- * Parse arguments, set some values, and pass control off to Run().
- *
- * This is redefined to "SDL_main" on SDL simulator builds, and
- * "runtime_main" on wxWidgets builds.
- */
-extern "C"
-int main(int argc, char* const argv[])
-{
- bool singleProcess = false;
- const char* logFile = NULL;
- int ic;
- int result = 1;
- pid_t systemPid;
-
- sp<ProcessState> proc;
-
-#ifndef HAVE_ANDROID_OS
- /* Set stdout/stderr to unbuffered for MinGW/MSYS. */
- //setvbuf(stdout, NULL, _IONBF, 0);
- //setvbuf(stderr, NULL, _IONBF, 0);
-
- LOGI("commandline args:\n");
- for (int i = 0; i < argc; i++)
- LOGI(" %2d: '%s'\n", i, argv[i]);
-#endif
-
- while (1) {
- ic = getopt(argc, argv, "g:j:v:d:l:ns");
- if (ic < 0)
- break;
-
- switch (ic) {
- case 'g':
- break;
- case 'j':
- gInitialApplication = optarg;
- break;
- case 'v':
- gInitialVerb = optarg;
- break;
- case 'd':
- gInitialData = optarg;
- break;
- case 'l':
- logFile = optarg;
- break;
- case 'n':
- redirectStdFds();
- break;
- case 's':
- singleProcess = true;
- break;
- case '?':
- default:
- LOGE("runtime: unrecognized flag -%c\n", ic);
- usage(argv[0]);
- break;
- }
- }
- if (optind < argc) {
- LOGE("runtime: extra stuff: %s\n", argv[optind]);
- usage(argv[0]);
- }
-
- if (singleProcess) {
- ProcessState::setSingleProcess(true);
- }
-
- if (logFile != NULL) {
- android_logToFile(NULL, logFile);
- }
-
- /*
- * Set up ANDROID_* environment variables.
- *
- * TODO: the use of $ANDROID_PRODUCT_OUT will go away soon.
- */
- static const char* kSystemDir = "/system";
- static const char* kDataDir = "/data";
- static const char* kAppSubdir = "/app";
- const char* out = NULL;
-#ifndef HAVE_ANDROID_OS
- //out = getenv("ANDROID_PRODUCT_OUT");
-#endif
- if (out == NULL)
- out = "";
-
- char* systemDir = (char*) malloc(strlen(out) + strlen(kSystemDir) +1);
- char* dataDir = (char*) malloc(strlen(out) + strlen(kDataDir) +1);
-
- sprintf(systemDir, "%s%s", out, kSystemDir);
- sprintf(dataDir, "%s%s", out, kDataDir);
- setenv("ANDROID_ROOT", systemDir, 1);
- setenv("ANDROID_DATA", dataDir, 1);
-
- char* assetDir = (char*) malloc(strlen(systemDir) + strlen(kAppSubdir) +1);
- sprintf(assetDir, "%s%s", systemDir, kAppSubdir);
-
- LOGI("Startup: sys='%s' asset='%s' data='%s'\n",
- systemDir, assetDir, dataDir);
- free(systemDir);
- free(dataDir);
-
-#ifdef HAVE_ANDROID_OS
- /* set up a process group for easier killing on the device */
- setpgid(0, getpid());
-#endif
-
- // Change to asset dir. This is only necessary if we've changed to
- // a different directory, but there's little harm in doing it regardless.
- //
- // Expecting assets to live in the current dir is not a great idea,
- // because some of our code or one of our libraries could change the
- // directory out from under us. Preserve the behavior for now.
- if (chdir(assetDir) != 0) {
- LOGW("WARNING: could not change dir to '%s': %s\n",
- assetDir, strerror(errno));
- }
- free(assetDir);
-
-#if 0
- // Hack to keep libc from beating the filesystem to death. It's
- // hitting /etc/localtime frequently,
- //
- // This statement locks us into Pacific time. We could do better,
- // but there's not much point until we're sure that the library
- // can't be changed to do more along the lines of what we want.
-#ifndef XP_WIN
- setenv("TZ", "PST+8PDT,M4.1.0/2,M10.5.0/2", true);
-#endif
-#endif
-
- /* track our progress through the boot sequence */
- const int LOG_BOOT_PROGRESS_START = 3000;
- LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
- ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
-
- validateTime();
-
- proc = ProcessState::self();
-
- boot_init();
-
- /* If we are in multiprocess mode, have zygote spawn the system
- * server process and call system_init(). If we are running in
- * single process mode just call system_init() directly.
- */
- if (proc->supportsProcesses()) {
- // If stdio logging is on, system_server should not inherit our stdio
- // The dalvikvm instance will copy stdio to the log on its own
- char propBuf[PROPERTY_VALUE_MAX];
- bool logStdio = false;
- property_get("log.redirect-stdio", propBuf, "");
- logStdio = (strcmp(propBuf, "true") == 0);
-
- zygote_run_oneshot((int)(!logStdio),
- sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),
- ZYGOTE_ARGV);
-
- //start_process("/system/bin/mediaserver");
-
- } else {
-#ifndef HAVE_ANDROID_OS
- QuickRuntime* runt = new QuickRuntime();
- runt->start("com/android/server/SystemServer",
- "" /* spontaneously fork system server from zygote */);
-#endif
- }
-
- //printf("+++ post-zygote\n");
-
- finish_system_init(proc);
- run(proc);
-
-bail:
- if (proc != NULL) {
- proc->setContextObject(NULL);
- }
-
- return 0;
-}
diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp
index a19711e..59360d3 100644
--- a/cmds/system_server/library/system_init.cpp
+++ b/cmds/system_server/library/system_init.cpp
@@ -76,23 +76,6 @@
SensorService::instantiate();
}
- // On the simulator, audioflinger et al don't get started the
- // same way as on the device, and we need to start them here
- if (!proc->supportsProcesses()) {
-
- // Start the AudioFlinger
- AudioFlinger::instantiate();
-
- // Start the media playback service
- MediaPlayerService::instantiate();
-
- // Start the camera service
- CameraService::instantiate();
-
- // Start the audio policy service
- AudioPolicyService::instantiate();
- }
-
// And now start the Android runtime. We have to do this bit
// of nastiness because the Android runtime initialization requires
// some of the core system services to already be started.
@@ -117,14 +100,10 @@
}
env->CallStaticVoidMethod(clazz, methodId);
- // If running in our own process, just go into the thread
- // pool. Otherwise, call the initialization finished
- // func to let this process continue its initilization.
- if (proc->supportsProcesses()) {
- LOGI("System server: entering thread pool.\n");
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- LOGI("System server: exiting thread pool.\n");
- }
+ LOGI("System server: entering thread pool.\n");
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ LOGI("System server: exiting thread pool.\n");
+
return NO_ERROR;
}
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index d77dbdc..e6c2a0f 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -87,11 +87,13 @@
private AnimatorSetListener mSetListener = null;
/**
- * Flag indicating that the AnimatorSet has been canceled (by calling cancel() or end()).
+ * Flag indicating that the AnimatorSet has been manually
+ * terminated (by calling cancel() or end()).
* This flag is used to avoid starting other animations when currently-playing
- * child animations of this AnimatorSet end.
+ * child animations of this AnimatorSet end. It also determines whether cancel/end
+ * notifications are sent out via the normal AnimatorSetListener mechanism.
*/
- boolean mCanceled = false;
+ boolean mTerminated = false;
// The amount of time in ms to delay starting the animation after start() is called
private long mStartDelay = 0;
@@ -271,31 +273,29 @@
@SuppressWarnings("unchecked")
@Override
public void cancel() {
- mCanceled = true;
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- for (AnimatorListener listener : tmpListeners) {
- listener.onAnimationCancel(this);
- }
- }
- if (mDelayAnim != null && mDelayAnim.isRunning()) {
- // If we're currently in the startDelay period, just cancel that animator and
- // send out the end event to all listeners
- mDelayAnim.cancel();
+ mTerminated = true;
+ if (isRunning()) {
+ ArrayList<AnimatorListener> tmpListeners = null;
if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
+ tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
+ for (AnimatorListener listener : tmpListeners) {
+ listener.onAnimationCancel(this);
+ }
+ }
+ if (mDelayAnim != null && mDelayAnim.isRunning()) {
+ // If we're currently in the startDelay period, just cancel that animator and
+ // send out the end event to all listeners
+ mDelayAnim.cancel();
+ } else if (mSortedNodes.size() > 0) {
+ for (Node node : mSortedNodes) {
+ node.animation.cancel();
+ }
+ }
+ if (tmpListeners != null) {
for (AnimatorListener listener : tmpListeners) {
listener.onAnimationEnd(this);
}
}
- return;
- }
- if (mSortedNodes.size() > 0) {
- for (Node node : mSortedNodes) {
- node.animation.cancel();
- }
}
}
@@ -307,23 +307,32 @@
*/
@Override
public void end() {
- mCanceled = true;
- if (mSortedNodes.size() != mNodes.size()) {
- // hasn't been started yet - sort the nodes now, then end them
- sortNodes();
- for (Node node : mSortedNodes) {
- if (mSetListener == null) {
- mSetListener = new AnimatorSetListener(this);
+ mTerminated = true;
+ if (isRunning()) {
+ if (mSortedNodes.size() != mNodes.size()) {
+ // hasn't been started yet - sort the nodes now, then end them
+ sortNodes();
+ for (Node node : mSortedNodes) {
+ if (mSetListener == null) {
+ mSetListener = new AnimatorSetListener(this);
+ }
+ node.animation.addListener(mSetListener);
}
- node.animation.addListener(mSetListener);
}
- }
- if (mDelayAnim != null) {
- mDelayAnim.cancel();
- }
- if (mSortedNodes.size() > 0) {
- for (Node node : mSortedNodes) {
- node.animation.end();
+ if (mDelayAnim != null) {
+ mDelayAnim.cancel();
+ }
+ if (mSortedNodes.size() > 0) {
+ for (Node node : mSortedNodes) {
+ node.animation.end();
+ }
+ }
+ if (mListeners != null) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ for (AnimatorListener listener : tmpListeners) {
+ listener.onAnimationEnd(this);
+ }
}
}
}
@@ -424,7 +433,7 @@
@SuppressWarnings("unchecked")
@Override
public void start() {
- mCanceled = false;
+ mTerminated = false;
// First, sort the nodes (if necessary). This will ensure that sortedNodes
// contains the animation nodes in the correct order.
@@ -437,7 +446,8 @@
ArrayList<AnimatorListener> oldListeners = node.animation.getListeners();
if (oldListeners != null && oldListeners.size() > 0) {
for (AnimatorListener listener : oldListeners) {
- if (listener instanceof DependencyListener) {
+ if (listener instanceof DependencyListener ||
+ listener instanceof AnimatorSetListener) {
node.animation.removeListener(listener);
}
}
@@ -522,7 +532,7 @@
* and will populate any appropriate lists, when it is started.
*/
anim.mNeedsSort = true;
- anim.mCanceled = false;
+ anim.mTerminated = false;
anim.mPlayingSet = new ArrayList<Animator>();
anim.mNodeMap = new HashMap<Animator, Node>();
anim.mNodes = new ArrayList<Node>();
@@ -640,7 +650,7 @@
* @param dependencyAnimation the animation that sent the event.
*/
private void startIfReady(Animator dependencyAnimation) {
- if (mAnimatorSet.mCanceled) {
+ if (mAnimatorSet.mTerminated) {
// if the parent AnimatorSet was canceled, then don't start any dependent anims
return;
}
@@ -676,11 +686,15 @@
}
public void onAnimationCancel(Animator animation) {
- if (mPlayingSet.size() == 0) {
- if (mListeners != null) {
- int numListeners = mListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- mListeners.get(i).onAnimationCancel(mAnimatorSet);
+ if (!mTerminated) {
+ // Listeners are already notified of the AnimatorSet canceling in cancel().
+ // The logic below only kicks in when animations end normally
+ if (mPlayingSet.size() == 0) {
+ if (mListeners != null) {
+ int numListeners = mListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ mListeners.get(i).onAnimationCancel(mAnimatorSet);
+ }
}
}
}
@@ -692,24 +706,28 @@
mPlayingSet.remove(animation);
Node animNode = mAnimatorSet.mNodeMap.get(animation);
animNode.done = true;
- ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
- boolean allDone = true;
- int numSortedNodes = sortedNodes.size();
- for (int i = 0; i < numSortedNodes; ++i) {
- if (!sortedNodes.get(i).done) {
- allDone = false;
- break;
+ if (!mTerminated) {
+ // Listeners are already notified of the AnimatorSet ending in cancel() or
+ // end(); the logic below only kicks in when animations end normally
+ ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
+ boolean allDone = true;
+ int numSortedNodes = sortedNodes.size();
+ for (int i = 0; i < numSortedNodes; ++i) {
+ if (!sortedNodes.get(i).done) {
+ allDone = false;
+ break;
+ }
}
- }
- if (allDone) {
- // If this was the last child animation to end, then notify listeners that this
- // AnimatorSet has ended
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
+ if (allDone) {
+ // If this was the last child animation to end, then notify listeners that this
+ // AnimatorSet has ended
+ if (mListeners != null) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
+ }
}
}
}
@@ -791,6 +809,8 @@
}
}
}
+ // nodes are 'done' by default; they become un-done when started, and done
+ // again when ended
node.done = false;
}
}
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 1dcaa04..90d676e 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -933,17 +933,17 @@
@Override
public void cancel() {
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- for (AnimatorListener listener : tmpListeners) {
- listener.onAnimationCancel(this);
- }
- }
// Only cancel if the animation is actually running or has been started and is about
// to run
if (mPlayingState != STOPPED || sPendingAnimations.get().contains(this) ||
sDelayedAnims.get().contains(this)) {
+ if (mListeners != null) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ for (AnimatorListener listener : tmpListeners) {
+ listener.onAnimationCancel(this);
+ }
+ }
endAnimation();
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a6658cc..d207a0a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1471,6 +1471,24 @@
}
/**
+ * Returns the usage statistics of each installed package.
+ *
+ * @hide
+ */
+ public PkgUsageStats[] getAllPackageUsageStats() {
+ try {
+ IUsageStats usageStatsService = IUsageStats.Stub.asInterface(
+ ServiceManager.getService("usagestats"));
+ if (usageStatsService != null) {
+ return usageStatsService.getAllPkgUsageStats();
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not query usage stats", e);
+ }
+ return new PkgUsageStats[0];
+ }
+
+ /**
* @param userid the user's id. Zero indicates the default user
* @hide
*/
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index eee14fb..ee04729 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4093,11 +4093,6 @@
});
}
- private final void detach()
- {
- sThreadLocal.set(null);
- }
-
public static final ActivityThread systemMain() {
HardwareRenderer.disable();
ActivityThread thread = new ActivityThread();
@@ -4105,10 +4100,9 @@
return thread;
}
- public final void installSystemProviders(List providers) {
+ public final void installSystemProviders(List<ProviderInfo> providers) {
if (providers != null) {
- installContentProviders(mInitialApplication,
- (List<ProviderInfo>)providers);
+ installContentProviders(mInitialApplication, providers);
}
}
@@ -4147,14 +4141,6 @@
Looper.loop();
- if (Process.supportsProcesses()) {
- throw new RuntimeException("Main thread loop unexpectedly exited");
- }
-
- thread.detach();
- String name = (thread.mInitialApplication != null)
- ? thread.mInitialApplication.getPackageName()
- : "<unknown>";
- Slog.i(TAG, "Main thread of " + name + " is now exiting");
+ throw new RuntimeException("Main thread loop unexpectedly exited");
}
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8749d3e..d2323e7 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1163,9 +1163,6 @@
throw new IllegalArgumentException("permission is null");
}
- if (!Process.supportsProcesses()) {
- return PackageManager.PERMISSION_GRANTED;
- }
try {
return ActivityManagerNative.getDefault().checkPermission(
permission, pid, uid);
@@ -1180,9 +1177,6 @@
throw new IllegalArgumentException("permission is null");
}
- if (!Process.supportsProcesses()) {
- return PackageManager.PERMISSION_GRANTED;
- }
int pid = Binder.getCallingPid();
if (pid != Process.myPid()) {
return checkPermission(permission, pid,
@@ -1263,9 +1257,6 @@
@Override
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
- if (!Process.supportsProcesses()) {
- return PackageManager.PERMISSION_GRANTED;
- }
try {
return ActivityManagerNative.getDefault().checkUriPermission(
uri, pid, uid, modeFlags);
@@ -1276,9 +1267,6 @@
@Override
public int checkCallingUriPermission(Uri uri, int modeFlags) {
- if (!Process.supportsProcesses()) {
- return PackageManager.PERMISSION_GRANTED;
- }
int pid = Binder.getCallingPid();
if (pid != Process.myPid()) {
return checkUriPermission(uri, pid,
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 52efc07..0a01dcf 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -16,7 +16,6 @@
package android.bluetooth;
-import android.annotation.SdkConstant;
import android.content.Context;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -67,9 +66,6 @@
*/
public static final int CHANNEL_TYPE_ANY = 12;
- private final ArrayList<BluetoothHealthAppConfiguration> mAppConfigs =
- new ArrayList<BluetoothHealthAppConfiguration>();
-
/**
* Register an application configuration that acts as a Health SINK.
* This is the configuration that will be used to communicate with health devices
@@ -86,7 +82,7 @@
* @return If true, callback will be called.
*/
public boolean registerSinkAppConfiguration(String name, int dataType,
- IBluetoothHealthCallback callback) {
+ BluetoothHealthCallback callback) {
if (!isEnabled() || name == null) return false;
if (DBG) log("registerSinkApplication(" + name + ":" + dataType + ")");
@@ -111,18 +107,18 @@
* @hide
*/
public boolean registerAppConfiguration(String name, int dataType, int role,
- int channelType, IBluetoothHealthCallback callback) {
+ int channelType, BluetoothHealthCallback callback) {
boolean result = false;
if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result;
if (DBG) log("registerApplication(" + name + ":" + dataType + ")");
+ BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback);
BluetoothHealthAppConfiguration config =
- new BluetoothHealthAppConfiguration(name, dataType, role, channelType,
- callback);
+ new BluetoothHealthAppConfiguration(name, dataType, role, channelType);
if (mService != null) {
try {
- result = mService.registerAppConfiguration(config);
+ result = mService.registerAppConfiguration(config, wrapper);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -130,8 +126,6 @@
Log.w(TAG, "Proxy not attached to service");
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
}
-
- if (result) mAppConfigs.add(config);
return result;
}
@@ -147,7 +141,7 @@
*/
public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
boolean result = false;
- if (mService != null && isEnabled() && isValidAppConfig(config)) {
+ if (mService != null && isEnabled() && config != null) {
try {
result = mService.unregisterAppConfiguration(config);
} catch (RemoteException e) {
@@ -157,26 +151,26 @@
Log.w(TAG, "Proxy not attached to service");
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
}
- if (result) mAppConfigs.remove(config);
+
return result;
}
/**
* Connect to a health device which has the {@link #SOURCE_ROLE}.
- * This is an asynchrnous call. If this function returns true, the callback
+ * This is an asynchronous call. If this function returns true, the callback
* associated with the application configuration will be called.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device The remote Bluetooth device.
- * @param config The application configuration which has been registed using
- * {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
+ * @param config The application configuration which has been registered using
+ * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
* @return If true, the callback associated with the application config will be called.
*/
public boolean connectChannelToSource(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
if (mService != null && isEnabled() && isValidDevice(device) &&
- isValidAppConfig(config)) {
+ config != null) {
try {
return mService.connectChannelToSource(device, config);
} catch (RemoteException e) {
@@ -197,15 +191,15 @@
*<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device The remote Bluetooth device.
- * @param config The application configuration which has been registed using
- * {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
+ * @param config The application configuration which has been registered using
+ * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
* @return If true, the callback associated with the application config will be called.
* @hide
*/
public boolean connectChannelToSink(BluetoothDevice device,
BluetoothHealthAppConfiguration config, int channelType) {
if (mService != null && isEnabled() && isValidDevice(device) &&
- isValidAppConfig(config)) {
+ config != null) {
try {
return mService.connectChannelToSink(device, config, channelType);
} catch (RemoteException e) {
@@ -226,8 +220,8 @@
*<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device The remote Bluetooth device.
- * @param config The application configuration which has been registed using
- * {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
+ * @param config The application configuration which has been registered using
+ * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
* @param fd The file descriptor that was associated with the channel.
* @return If true, the callback associated with the application config will be called.
* @hide
@@ -235,7 +229,7 @@
public boolean disconnectChannel(BluetoothDevice device,
BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
if (mService != null && isEnabled() && isValidDevice(device) &&
- isValidAppConfig(config)) {
+ config != null) {
try {
return mService.disconnectChannel(device, config, fd);
} catch (RemoteException e) {
@@ -262,7 +256,7 @@
public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
if (mService != null && isEnabled() && isValidDevice(device) &&
- isValidAppConfig(config)) {
+ config != null) {
try {
return mService.getMainChannelFd(device, config);
} catch (RemoteException e) {
@@ -290,6 +284,7 @@
* {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
*/
+ @Override
public int getConnectionState(BluetoothDevice device) {
if (mService != null && isEnabled() && isValidDevice(device)) {
try {
@@ -317,6 +312,7 @@
* local adapter.
* @return List of devices. The list will be empty on error.
*/
+ @Override
public List<BluetoothDevice> getConnectedDevices() {
if (mService != null && isEnabled()) {
try {
@@ -348,6 +344,7 @@
* {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
* @return List of devices. The list will be empty on error.
*/
+ @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (mService != null && isEnabled()) {
try {
@@ -361,6 +358,27 @@
return new ArrayList<BluetoothDevice>();
}
+ private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub {
+ private BluetoothHealthCallback mCallback;
+
+ public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
+ int status) {
+ mCallback.onHealthAppConfigurationStatusChange(config, status);
+ }
+
+ @Override
+ public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
+ BluetoothDevice device, int prevState, int newState,
+ ParcelFileDescriptor fd) {
+ mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd);
+ }
+ }
+
/** Health Channel Connection State - Disconnected */
public static final int STATE_CHANNEL_DISCONNECTED = 0;
/** Health Channel Connection State - Connecting */
@@ -379,7 +397,6 @@
/** Health App Configuration un-registration failure */
public static final int APPLICATION_UNREGISTRATION_FAILURE = 3;
- private Context mContext;
private ServiceListener mServiceListener;
private IBluetooth mService;
BluetoothAdapter mAdapter;
@@ -420,14 +437,8 @@
return false;
}
- private boolean isValidAppConfig(BluetoothHealthAppConfiguration config) {
- if (!mAppConfigs.isEmpty() && mAppConfigs.contains(config)) return true;
- log("Not a valid config: " + config);
- return false;
- }
-
private boolean checkAppParam(String name, int role, int channelType,
- IBluetoothHealthCallback callback) {
+ BluetoothHealthCallback callback) {
if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE) ||
(channelType != CHANNEL_TYPE_RELIABLE &&
channelType != CHANNEL_TYPE_STREAMING &&
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
index b87aea5..7020249 100644
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
@@ -17,7 +17,6 @@
package android.bluetooth;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,21 +33,18 @@
private final int mDataType;
private final int mRole;
private final int mChannelType;
- private final IBluetoothHealthCallback mCallback;
/**
* Constructor to register the SINK role
*
* @param name Friendly name associated with the application configuration
* @param dataType Data Type of the remote Bluetooth Health device
- * @param callback Callback associated with the application configuration.
*/
- BluetoothHealthAppConfiguration(String name, int dataType, IBluetoothHealthCallback callback) {
+ BluetoothHealthAppConfiguration(String name, int dataType) {
mName = name;
mDataType = dataType;
mRole = BluetoothHealth.SINK_ROLE;
mChannelType = BluetoothHealth.CHANNEL_TYPE_ANY;
- mCallback = callback;
}
/**
@@ -56,17 +52,15 @@
*
* @param name Friendly name associated with the application configuration
* @param dataType Data Type of the remote Bluetooth Health device
- * @param role {@link BluetoothHealth.SOURCE_ROLE} or
- * {@link BluetoothHealth.SINK_ROLE}
- * @param callback Callback associated with the application configuration.
+ * @param role {@link BluetoothHealth#SOURCE_ROLE} or
+ * {@link BluetoothHealth#SINK_ROLE}
*/
- BluetoothHealthAppConfiguration(String name, int dataType, int role, int channelType,
- IBluetoothHealthCallback callback) {
+ BluetoothHealthAppConfiguration(String name, int dataType, int role, int
+ channelType) {
mName = name;
mDataType = dataType;
mRole = role;
mChannelType = channelType;
- mCallback = callback;
}
@Override
@@ -77,8 +71,7 @@
return mName.equals(config.getName()) &&
mDataType == config.getDataType() &&
mRole == config.getRole() &&
- mChannelType == config.getChannelType() &&
- mCallback.equals(config.getCallback());
+ mChannelType == config.getChannelType();
}
return false;
}
@@ -90,7 +83,6 @@
result = 31 * result + mDataType;
result = 31 * result + mRole;
result = 31 * result + mChannelType;
- result = 31 * result + (mCallback != null ? mCallback.hashCode() : 0);
return result;
}
@@ -98,9 +90,10 @@
public String toString() {
return "BluetoothHealthAppConfiguration [mName = " + mName +
",mDataType = " + mDataType + ", mRole = " + mRole + ",mChannelType = " +
- mChannelType + ",callback=" + mCallback +"]";
+ mChannelType + "]";
}
+ @Override
public int describeContents() {
return 0;
}
@@ -144,37 +137,31 @@
return mChannelType;
}
- /**
- * Return the callback associated with this application configuration.
- *
- * @return IBluetoothHealthCallback
- */
- public IBluetoothHealthCallback getCallback() {
- return mCallback;
- }
-
public static final Parcelable.Creator<BluetoothHealthAppConfiguration> CREATOR =
new Parcelable.Creator<BluetoothHealthAppConfiguration>() {
+ @Override
public BluetoothHealthAppConfiguration createFromParcel(Parcel in) {
String name = in.readString();
int type = in.readInt();
int role = in.readInt();
int channelType = in.readInt();
- IBluetoothHealthCallback callback =
- IBluetoothHealthCallback.Stub.asInterface(in.readStrongBinder());
- return new BluetoothHealthAppConfiguration(name, type, role, channelType,
- callback);
+ return new BluetoothHealthAppConfiguration(name, type, role,
+ channelType);
}
+
+ @Override
public BluetoothHealthAppConfiguration[] newArray(int size) {
return new BluetoothHealthAppConfiguration[size];
}
};
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(mName);
out.writeInt(mDataType);
out.writeInt(mRole);
out.writeInt(mChannelType);
- out.writeStrongInterface(mCallback);
}
+
+
}
diff --git a/core/java/android/bluetooth/BluetoothHealthCallback.java b/core/java/android/bluetooth/BluetoothHealthCallback.java
new file mode 100644
index 0000000..0d11bb5
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHealthCallback.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.bluetooth;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+/**
+ * This class is used for all the {@link BluetoothHealth} callbacks.
+ * @hide
+ */
+public abstract class BluetoothHealthCallback {
+
+ private static final String TAG = "BluetoothHealthCallback";
+
+ public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
+ int status) {
+ Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + " Status:" + status);
+ }
+
+ public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
+ BluetoothDevice device, int prevState, int newState,
+ ParcelFileDescriptor fd) {
+ Log.d(TAG, "onHealthChannelStateChange: " + config + " Device:" + device +
+ "PrevState:" + prevState + "NewState:" + newState + "FileDescriptor:" + fd);
+ }
+}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 6ca6c2e..183772d 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothHealthCallback;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHealthAppConfiguration;
import android.os.ParcelUuid;
@@ -102,7 +103,8 @@
boolean disconnectPanDevice(in BluetoothDevice device);
// HDP profile APIs
- boolean registerAppConfiguration(in BluetoothHealthAppConfiguration config);
+ boolean registerAppConfiguration(in BluetoothHealthAppConfiguration config,
+ in IBluetoothHealthCallback callback);
boolean unregisterAppConfiguration(in BluetoothHealthAppConfiguration config);
boolean connectChannelToSource(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
boolean connectChannelToSink(in BluetoothDevice device, in BluetoothHealthAppConfiguration config,
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 9d40c42..a4c66e4 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -43,17 +43,41 @@
/** {@link #tag} value for without tag. */
public static final int TAG_NONE = 0;
+ // TODO: move public fields to Entry accessors, then undeprecate
+ // TODO: refactor rx/tx to rxBytes/txBytes
+
/**
* {@link SystemClock#elapsedRealtime()} timestamp when this data was
* generated.
*/
+ @Deprecated
public final long elapsedRealtime;
+ @Deprecated
public int size;
+ @Deprecated
public String[] iface;
+ @Deprecated
public int[] uid;
+ @Deprecated
public int[] tag;
+ @Deprecated
public long[] rx;
+ @Deprecated
+ public long[] rxPackets;
+ @Deprecated
public long[] tx;
+ @Deprecated
+ public long[] txPackets;
+
+ public static class Entry {
+ public String iface;
+ public int uid;
+ public int tag;
+ public long rxBytes;
+ public long rxPackets;
+ public long txBytes;
+ public long txPackets;
+ }
public NetworkStats(long elapsedRealtime, int initialSize) {
this.elapsedRealtime = elapsedRealtime;
@@ -62,7 +86,9 @@
this.uid = new int[initialSize];
this.tag = new int[initialSize];
this.rx = new long[initialSize];
+ this.rxPackets = new long[initialSize];
this.tx = new long[initialSize];
+ this.txPackets = new long[initialSize];
}
public NetworkStats(Parcel parcel) {
@@ -72,38 +98,82 @@
uid = parcel.createIntArray();
tag = parcel.createIntArray();
rx = parcel.createLongArray();
+ rxPackets = parcel.createLongArray();
tx = parcel.createLongArray();
+ txPackets = parcel.createLongArray();
}
/**
* Add new stats entry with given values.
*/
public NetworkStats addEntry(String iface, int uid, int tag, long rx, long tx) {
+ final Entry entry = new Entry();
+ entry.iface = iface;
+ entry.uid = uid;
+ entry.tag = tag;
+ entry.rxBytes = rx;
+ entry.txBytes = tx;
+ return addValues(entry);
+ }
+
+ /**
+ * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
+ * object can be recycled across multiple calls.
+ */
+ public NetworkStats addValues(Entry entry) {
if (size >= this.iface.length) {
- final int newLength = Math.max(this.iface.length, 10) * 3 / 2;
- this.iface = Arrays.copyOf(this.iface, newLength);
- this.uid = Arrays.copyOf(this.uid, newLength);
- this.tag = Arrays.copyOf(this.tag, newLength);
- this.rx = Arrays.copyOf(this.rx, newLength);
- this.tx = Arrays.copyOf(this.tx, newLength);
+ final int newLength = Math.max(iface.length, 10) * 3 / 2;
+ iface = Arrays.copyOf(iface, newLength);
+ uid = Arrays.copyOf(uid, newLength);
+ tag = Arrays.copyOf(tag, newLength);
+ rx = Arrays.copyOf(rx, newLength);
+ rxPackets = Arrays.copyOf(rxPackets, newLength);
+ tx = Arrays.copyOf(tx, newLength);
+ txPackets = Arrays.copyOf(txPackets, newLength);
}
- this.iface[size] = iface;
- this.uid[size] = uid;
- this.tag[size] = tag;
- this.rx[size] = rx;
- this.tx[size] = tx;
+ iface[size] = entry.iface;
+ uid[size] = entry.uid;
+ tag[size] = entry.tag;
+ rx[size] = entry.rxBytes;
+ rxPackets[size] = entry.rxPackets;
+ tx[size] = entry.txBytes;
+ txPackets[size] = entry.txPackets;
size++;
return this;
}
/**
+ * Return specific stats entry.
+ */
+ public Entry getValues(int i, Entry recycle) {
+ final Entry entry = recycle != null ? recycle : new Entry();
+ entry.iface = iface[i];
+ entry.uid = uid[i];
+ entry.tag = tag[i];
+ entry.rxBytes = rx[i];
+ entry.rxPackets = rxPackets[i];
+ entry.txBytes = tx[i];
+ entry.txPackets = txPackets[i];
+ return entry;
+ }
+
+ public long getElapsedRealtime() {
+ return elapsedRealtime;
+ }
+
+ public int size() {
+ return size;
+ }
+
+ /**
* Combine given values with an existing row, or create a new row if
* {@link #findIndex(String, int, int)} is unable to find match. Can also be
* used to subtract values from existing rows.
*/
public NetworkStats combineEntry(String iface, int uid, int tag, long rx, long tx) {
+ // TODO: extent to accept rxPackets/txPackets
final int i = findIndex(iface, uid, tag);
if (i == -1) {
// only create new entry when positive contribution
@@ -199,30 +269,41 @@
}
// result will have our rows, and elapsed time between snapshots
+ final Entry entry = new Entry();
final NetworkStats result = new NetworkStats(deltaRealtime, size);
for (int i = 0; i < size; i++) {
- final String iface = this.iface[i];
- final int uid = this.uid[i];
- final int tag = this.tag[i];
+ entry.iface = iface[i];
+ entry.uid = uid[i];
+ entry.tag = tag[i];
// find remote row that matches, and subtract
- final int j = value.findIndex(iface, uid, tag);
+ final int j = value.findIndex(entry.iface, entry.uid, entry.tag);
if (j == -1) {
// newly appearing row, return entire value
- result.addEntry(iface, uid, tag, this.rx[i], this.tx[i]);
+ entry.rxBytes = rx[i];
+ entry.rxPackets = rxPackets[i];
+ entry.txBytes = tx[i];
+ entry.txPackets = txPackets[i];
} else {
// existing row, subtract remote value
- long rx = this.rx[i] - value.rx[j];
- long tx = this.tx[i] - value.tx[j];
- if (enforceMonotonic && (rx < 0 || tx < 0)) {
+ entry.rxBytes = rx[i] - value.rx[j];
+ entry.rxPackets = rxPackets[i] - value.rxPackets[j];
+ entry.txBytes = tx[i] - value.tx[j];
+ entry.txPackets = txPackets[i] - value.txPackets[j];
+ if (enforceMonotonic
+ && (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
+ || entry.txPackets < 0)) {
throw new IllegalArgumentException("found non-monotonic values");
}
if (clampNegative) {
- rx = Math.max(0, rx);
- tx = Math.max(0, tx);
+ entry.rxBytes = Math.max(0, entry.rxBytes);
+ entry.rxPackets = Math.max(0, entry.rxPackets);
+ entry.txBytes = Math.max(0, entry.txBytes);
+ entry.txPackets = Math.max(0, entry.txPackets);
}
- result.addEntry(iface, uid, tag, rx, tx);
}
+
+ result.addValues(entry);
}
return result;
@@ -235,13 +316,15 @@
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
- for (int i = 0; i < iface.length; i++) {
+ for (int i = 0; i < size; i++) {
pw.print(prefix);
pw.print(" iface="); pw.print(iface[i]);
pw.print(" uid="); pw.print(uid[i]);
pw.print(" tag="); pw.print(tag[i]);
- pw.print(" rx="); pw.print(rx[i]);
- pw.print(" tx="); pw.println(tx[i]);
+ pw.print(" rxBytes="); pw.print(rx[i]);
+ pw.print(" rxPackets="); pw.print(rxPackets[i]);
+ pw.print(" txBytes="); pw.print(tx[i]);
+ pw.print(" txPackets="); pw.println(txPackets[i]);
}
}
@@ -265,7 +348,9 @@
dest.writeIntArray(uid);
dest.writeIntArray(tag);
dest.writeLongArray(rx);
+ dest.writeLongArray(rxPackets);
dest.writeLongArray(tx);
+ dest.writeLongArray(txPackets);
}
public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 3edd692..c0be664 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -86,9 +86,7 @@
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
- if (Process.supportsProcesses()) {
- myLooper().mQueue.mQuitAllowed = false;
- }
+ myLooper().mQueue.mQuitAllowed = false;
}
private synchronized static void setMainLooper(Looper looper) {
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index dbefb1f..5b1f563 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -270,82 +270,25 @@
* @param targetSdkVersion The target SDK version for the app.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
- * @return int If > 0 the pid of the new process; if 0 the process is
- * being emulated by a thread
+ * @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
*
* {@hide}
*/
- public static final int start(final String processClass,
+ public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int targetSdkVersion,
- String[] zygoteArgs)
- {
- if (supportsProcesses()) {
- try {
- return startViaZygote(processClass, niceName, uid, gid, gids,
- debugFlags, targetSdkVersion, zygoteArgs);
- } catch (ZygoteStartFailedEx ex) {
- Log.e(LOG_TAG,
- "Starting VM process through Zygote failed");
- throw new RuntimeException(
- "Starting VM process through Zygote failed", ex);
- }
- } else {
- // Running in single-process mode
-
- Runnable runnable = new Runnable() {
- public void run() {
- Process.invokeStaticMain(processClass);
- }
- };
-
- // Thread constructors must not be called with null names (see spec).
- if (niceName != null) {
- new Thread(runnable, niceName).start();
- } else {
- new Thread(runnable).start();
- }
-
- return 0;
- }
- }
-
- /**
- * Start a new process. Don't supply a custom nice name.
- * {@hide}
- */
- public static final int start(String processClass, int uid, int gid,
- int[] gids, int debugFlags, int targetSdkVersion,
- String[] zygoteArgs) {
- return start(processClass, "", uid, gid, gids,
- debugFlags, targetSdkVersion, zygoteArgs);
- }
-
- private static void invokeStaticMain(String className) {
- Class cl;
- Object args[] = new Object[1];
-
- args[0] = new String[0]; //this is argv
-
+ String[] zygoteArgs) {
try {
- cl = Class.forName(className);
- cl.getMethod("main", new Class[] { String[].class })
- .invoke(null, args);
- } catch (Exception ex) {
- // can be: ClassNotFoundException,
- // NoSuchMethodException, SecurityException,
- // IllegalAccessException, IllegalArgumentException
- // InvocationTargetException
- // or uncaught exception from main()
-
- Log.e(LOG_TAG, "Exception invoking static main on "
- + className, ex);
-
- throw new RuntimeException(ex);
+ return startViaZygote(processClass, niceName, uid, gid, gids,
+ debugFlags, targetSdkVersion, zygoteArgs);
+ } catch (ZygoteStartFailedEx ex) {
+ Log.e(LOG_TAG,
+ "Starting VM process through Zygote failed");
+ throw new RuntimeException(
+ "Starting VM process through Zygote failed", ex);
}
-
}
/** retry interval for opening a zygote socket */
@@ -432,14 +375,11 @@
* and returns the child's pid. Please note: the present implementation
* replaces newlines in the argument list with spaces.
* @param args argument list
- * @return PID of new child process
+ * @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
- private static int zygoteSendArgsAndGetPid(ArrayList<String> args)
+ private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
throws ZygoteStartFailedEx {
-
- int pid;
-
openZygoteSocketIfNeeded();
try {
@@ -450,7 +390,8 @@
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
- * the child or -1 on failure.
+ * the child or -1 on failure, followed by boolean to
+ * indicate whether a wrapper process was used.
*/
sZygoteWriter.write(Integer.toString(args.size()));
@@ -470,11 +411,13 @@
sZygoteWriter.flush();
// Should there be a timeout on this?
- pid = sZygoteInputStream.readInt();
-
- if (pid < 0) {
+ ProcessStartResult result = new ProcessStartResult();
+ result.pid = sZygoteInputStream.readInt();
+ if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
+ result.usingWrapper = sZygoteInputStream.readBoolean();
+ return result;
} catch (IOException ex) {
try {
if (sZygoteSocket != null) {
@@ -489,8 +432,6 @@
throw new ZygoteStartFailedEx(ex);
}
-
- return pid;
}
/**
@@ -505,18 +446,16 @@
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param extraArgs Additional arguments to supply to the zygote process.
- * @return PID
+ * @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
- private static int startViaZygote(final String processClass,
+ private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int targetSdkVersion,
String[] extraArgs)
throws ZygoteStartFailedEx {
- int pid;
-
synchronized(Process.class) {
ArrayList<String> argsForZygote = new ArrayList<String>();
@@ -572,15 +511,9 @@
argsForZygote.add(arg);
}
}
-
- pid = zygoteSendArgsAndGetPid(argsForZygote);
- }
- if (pid <= 0) {
- throw new ZygoteStartFailedEx("zygote start failed:" + pid);
+ return zygoteSendArgsAndGetResult(argsForZygote);
}
-
- return pid;
}
/**
@@ -740,8 +673,13 @@
*
* @return Returns true if the system can run in multiple processes, else
* false if everything is running in a single process.
+ *
+ * @deprecated This method always returns true. Do not use.
*/
- public static final native boolean supportsProcesses();
+ @Deprecated
+ public static final boolean supportsProcesses() {
+ return true;
+ }
/**
* Set the out-of-memory badness adjustment for a process.
@@ -859,4 +797,21 @@
* @hide
*/
public static final native long getPss(int pid);
+
+ /**
+ * Specifies the outcome of having started a process.
+ * @hide
+ */
+ public static final class ProcessStartResult {
+ /**
+ * The PID of the newly started process.
+ * Always >= 0. (If the start failed, an exception will have been thrown instead.)
+ */
+ public int pid;
+
+ /**
+ * True if the process was started with a wrapper attached.
+ */
+ public boolean usingWrapper;
+ }
}
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index b721665..1af24f4a 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -114,7 +114,7 @@
* @hide
*/
public static void initServiceCache(Map<String, IBinder> cache) {
- if (sCache.size() != 0 && Process.supportsProcesses()) {
+ if (sCache.size() != 0) {
throw new IllegalStateException("setServiceCache may only be called once");
}
sCache.putAll(cache);
diff --git a/core/java/android/pim/EventRecurrence.java b/core/java/android/pim/EventRecurrence.java
deleted file mode 100644
index 128b697..0000000
--- a/core/java/android/pim/EventRecurrence.java
+++ /dev/null
@@ -1,892 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim;
-
-import android.text.TextUtils;
-import android.text.format.Time;
-import android.util.Log;
-import android.util.TimeFormatException;
-
-import java.util.Calendar;
-import java.util.HashMap;
-
-/**
- * Event recurrence utility functions.
- */
-public class EventRecurrence {
- private static String TAG = "EventRecur";
-
- public static final int SECONDLY = 1;
- public static final int MINUTELY = 2;
- public static final int HOURLY = 3;
- public static final int DAILY = 4;
- public static final int WEEKLY = 5;
- public static final int MONTHLY = 6;
- public static final int YEARLY = 7;
-
- public static final int SU = 0x00010000;
- public static final int MO = 0x00020000;
- public static final int TU = 0x00040000;
- public static final int WE = 0x00080000;
- public static final int TH = 0x00100000;
- public static final int FR = 0x00200000;
- public static final int SA = 0x00400000;
-
- public Time startDate; // set by setStartDate(), not parse()
-
- public int freq; // SECONDLY, MINUTELY, etc.
- public String until;
- public int count;
- public int interval;
- public int wkst; // SU, MO, TU, etc.
-
- /* lists with zero entries may be null references */
- public int[] bysecond;
- public int bysecondCount;
- public int[] byminute;
- public int byminuteCount;
- public int[] byhour;
- public int byhourCount;
- public int[] byday;
- public int[] bydayNum;
- public int bydayCount;
- public int[] bymonthday;
- public int bymonthdayCount;
- public int[] byyearday;
- public int byyeardayCount;
- public int[] byweekno;
- public int byweeknoCount;
- public int[] bymonth;
- public int bymonthCount;
- public int[] bysetpos;
- public int bysetposCount;
-
- /** maps a part string to a parser object */
- private static HashMap<String,PartParser> sParsePartMap;
- static {
- sParsePartMap = new HashMap<String,PartParser>();
- sParsePartMap.put("FREQ", new ParseFreq());
- sParsePartMap.put("UNTIL", new ParseUntil());
- sParsePartMap.put("COUNT", new ParseCount());
- sParsePartMap.put("INTERVAL", new ParseInterval());
- sParsePartMap.put("BYSECOND", new ParseBySecond());
- sParsePartMap.put("BYMINUTE", new ParseByMinute());
- sParsePartMap.put("BYHOUR", new ParseByHour());
- sParsePartMap.put("BYDAY", new ParseByDay());
- sParsePartMap.put("BYMONTHDAY", new ParseByMonthDay());
- sParsePartMap.put("BYYEARDAY", new ParseByYearDay());
- sParsePartMap.put("BYWEEKNO", new ParseByWeekNo());
- sParsePartMap.put("BYMONTH", new ParseByMonth());
- sParsePartMap.put("BYSETPOS", new ParseBySetPos());
- sParsePartMap.put("WKST", new ParseWkst());
- }
-
- /* values for bit vector that keeps track of what we have already seen */
- private static final int PARSED_FREQ = 1 << 0;
- private static final int PARSED_UNTIL = 1 << 1;
- private static final int PARSED_COUNT = 1 << 2;
- private static final int PARSED_INTERVAL = 1 << 3;
- private static final int PARSED_BYSECOND = 1 << 4;
- private static final int PARSED_BYMINUTE = 1 << 5;
- private static final int PARSED_BYHOUR = 1 << 6;
- private static final int PARSED_BYDAY = 1 << 7;
- private static final int PARSED_BYMONTHDAY = 1 << 8;
- private static final int PARSED_BYYEARDAY = 1 << 9;
- private static final int PARSED_BYWEEKNO = 1 << 10;
- private static final int PARSED_BYMONTH = 1 << 11;
- private static final int PARSED_BYSETPOS = 1 << 12;
- private static final int PARSED_WKST = 1 << 13;
-
- /** maps a FREQ value to an integer constant */
- private static final HashMap<String,Integer> sParseFreqMap = new HashMap<String,Integer>();
- static {
- sParseFreqMap.put("SECONDLY", SECONDLY);
- sParseFreqMap.put("MINUTELY", MINUTELY);
- sParseFreqMap.put("HOURLY", HOURLY);
- sParseFreqMap.put("DAILY", DAILY);
- sParseFreqMap.put("WEEKLY", WEEKLY);
- sParseFreqMap.put("MONTHLY", MONTHLY);
- sParseFreqMap.put("YEARLY", YEARLY);
- }
-
- /** maps a two-character weekday string to an integer constant */
- private static final HashMap<String,Integer> sParseWeekdayMap = new HashMap<String,Integer>();
- static {
- sParseWeekdayMap.put("SU", SU);
- sParseWeekdayMap.put("MO", MO);
- sParseWeekdayMap.put("TU", TU);
- sParseWeekdayMap.put("WE", WE);
- sParseWeekdayMap.put("TH", TH);
- sParseWeekdayMap.put("FR", FR);
- sParseWeekdayMap.put("SA", SA);
- }
-
- /** If set, allow lower-case recurrence rule strings. Minor performance impact. */
- private static final boolean ALLOW_LOWER_CASE = false;
-
- /** If set, validate the value of UNTIL parts. Minor performance impact. */
- private static final boolean VALIDATE_UNTIL = false;
-
- /** If set, require that only one of {UNTIL,COUNT} is present. Breaks compat w/ old parser. */
- private static final boolean ONLY_ONE_UNTIL_COUNT = false;
-
-
- /**
- * Thrown when a recurrence string provided can not be parsed according
- * to RFC2445.
- */
- public static class InvalidFormatException extends RuntimeException {
- InvalidFormatException(String s) {
- super(s);
- }
- }
-
-
- public void setStartDate(Time date) {
- startDate = date;
- }
-
- /**
- * Converts one of the Calendar.SUNDAY constants to the SU, MO, etc.
- * constants. btw, I think we should switch to those here too, to
- * get rid of this function, if possible.
- */
- public static int calendarDay2Day(int day)
- {
- switch (day)
- {
- case Calendar.SUNDAY:
- return SU;
- case Calendar.MONDAY:
- return MO;
- case Calendar.TUESDAY:
- return TU;
- case Calendar.WEDNESDAY:
- return WE;
- case Calendar.THURSDAY:
- return TH;
- case Calendar.FRIDAY:
- return FR;
- case Calendar.SATURDAY:
- return SA;
- default:
- throw new RuntimeException("bad day of week: " + day);
- }
- }
-
- public static int timeDay2Day(int day)
- {
- switch (day)
- {
- case Time.SUNDAY:
- return SU;
- case Time.MONDAY:
- return MO;
- case Time.TUESDAY:
- return TU;
- case Time.WEDNESDAY:
- return WE;
- case Time.THURSDAY:
- return TH;
- case Time.FRIDAY:
- return FR;
- case Time.SATURDAY:
- return SA;
- default:
- throw new RuntimeException("bad day of week: " + day);
- }
- }
- public static int day2TimeDay(int day)
- {
- switch (day)
- {
- case SU:
- return Time.SUNDAY;
- case MO:
- return Time.MONDAY;
- case TU:
- return Time.TUESDAY;
- case WE:
- return Time.WEDNESDAY;
- case TH:
- return Time.THURSDAY;
- case FR:
- return Time.FRIDAY;
- case SA:
- return Time.SATURDAY;
- default:
- throw new RuntimeException("bad day of week: " + day);
- }
- }
-
- /**
- * Converts one of the SU, MO, etc. constants to the Calendar.SUNDAY
- * constants. btw, I think we should switch to those here too, to
- * get rid of this function, if possible.
- */
- public static int day2CalendarDay(int day)
- {
- switch (day)
- {
- case SU:
- return Calendar.SUNDAY;
- case MO:
- return Calendar.MONDAY;
- case TU:
- return Calendar.TUESDAY;
- case WE:
- return Calendar.WEDNESDAY;
- case TH:
- return Calendar.THURSDAY;
- case FR:
- return Calendar.FRIDAY;
- case SA:
- return Calendar.SATURDAY;
- default:
- throw new RuntimeException("bad day of week: " + day);
- }
- }
-
- /**
- * Converts one of the internal day constants (SU, MO, etc.) to the
- * two-letter string representing that constant.
- *
- * @param day one the internal constants SU, MO, etc.
- * @return the two-letter string for the day ("SU", "MO", etc.)
- *
- * @throws IllegalArgumentException Thrown if the day argument is not one of
- * the defined day constants.
- */
- private static String day2String(int day) {
- switch (day) {
- case SU:
- return "SU";
- case MO:
- return "MO";
- case TU:
- return "TU";
- case WE:
- return "WE";
- case TH:
- return "TH";
- case FR:
- return "FR";
- case SA:
- return "SA";
- default:
- throw new IllegalArgumentException("bad day argument: " + day);
- }
- }
-
- private static void appendNumbers(StringBuilder s, String label,
- int count, int[] values)
- {
- if (count > 0) {
- s.append(label);
- count--;
- for (int i=0; i<count; i++) {
- s.append(values[i]);
- s.append(",");
- }
- s.append(values[count]);
- }
- }
-
- private void appendByDay(StringBuilder s, int i)
- {
- int n = this.bydayNum[i];
- if (n != 0) {
- s.append(n);
- }
-
- String str = day2String(this.byday[i]);
- s.append(str);
- }
-
- @Override
- public String toString()
- {
- StringBuilder s = new StringBuilder();
-
- s.append("FREQ=");
- switch (this.freq)
- {
- case SECONDLY:
- s.append("SECONDLY");
- break;
- case MINUTELY:
- s.append("MINUTELY");
- break;
- case HOURLY:
- s.append("HOURLY");
- break;
- case DAILY:
- s.append("DAILY");
- break;
- case WEEKLY:
- s.append("WEEKLY");
- break;
- case MONTHLY:
- s.append("MONTHLY");
- break;
- case YEARLY:
- s.append("YEARLY");
- break;
- }
-
- if (!TextUtils.isEmpty(this.until)) {
- s.append(";UNTIL=");
- s.append(until);
- }
-
- if (this.count != 0) {
- s.append(";COUNT=");
- s.append(this.count);
- }
-
- if (this.interval != 0) {
- s.append(";INTERVAL=");
- s.append(this.interval);
- }
-
- if (this.wkst != 0) {
- s.append(";WKST=");
- s.append(day2String(this.wkst));
- }
-
- appendNumbers(s, ";BYSECOND=", this.bysecondCount, this.bysecond);
- appendNumbers(s, ";BYMINUTE=", this.byminuteCount, this.byminute);
- appendNumbers(s, ";BYSECOND=", this.byhourCount, this.byhour);
-
- // day
- int count = this.bydayCount;
- if (count > 0) {
- s.append(";BYDAY=");
- count--;
- for (int i=0; i<count; i++) {
- appendByDay(s, i);
- s.append(",");
- }
- appendByDay(s, count);
- }
-
- appendNumbers(s, ";BYMONTHDAY=", this.bymonthdayCount, this.bymonthday);
- appendNumbers(s, ";BYYEARDAY=", this.byyeardayCount, this.byyearday);
- appendNumbers(s, ";BYWEEKNO=", this.byweeknoCount, this.byweekno);
- appendNumbers(s, ";BYMONTH=", this.bymonthCount, this.bymonth);
- appendNumbers(s, ";BYSETPOS=", this.bysetposCount, this.bysetpos);
-
- return s.toString();
- }
-
- public boolean repeatsOnEveryWeekDay() {
- if (this.freq != WEEKLY) {
- return false;
- }
-
- int count = this.bydayCount;
- if (count != 5) {
- return false;
- }
-
- for (int i = 0 ; i < count ; i++) {
- int day = byday[i];
- if (day == SU || day == SA) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Determines whether this rule specifies a simple monthly rule by weekday, such as
- * "FREQ=MONTHLY;BYDAY=3TU" (the 3rd Tuesday of every month).
- * <p>
- * Negative days, e.g. "FREQ=MONTHLY;BYDAY=-1TU" (the last Tuesday of every month),
- * will cause "false" to be returned.
- * <p>
- * Rules that fire every week, such as "FREQ=MONTHLY;BYDAY=TU" (every Tuesday of every
- * month) will cause "false" to be returned. (Note these are usually expressed as
- * WEEKLY rules, and hence are uncommon.)
- *
- * @return true if this rule is of the appropriate form
- */
- public boolean repeatsMonthlyOnDayCount() {
- if (this.freq != MONTHLY) {
- return false;
- }
-
- if (bydayCount != 1 || bymonthdayCount != 0) {
- return false;
- }
-
- if (bydayNum[0] <= 0) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Determines whether two integer arrays contain identical elements.
- * <p>
- * The native implementation over-allocated the arrays (and may have stuff left over from
- * a previous run), so we can't just check the arrays -- the separately-maintained count
- * field also matters. We assume that a null array will have a count of zero, and that the
- * array can hold as many elements as the associated count indicates.
- * <p>
- * TODO: replace this with Arrays.equals() when the old parser goes away.
- */
- private static boolean arraysEqual(int[] array1, int count1, int[] array2, int count2) {
- if (count1 != count2) {
- return false;
- }
-
- for (int i = 0; i < count1; i++) {
- if (array1[i] != array2[i])
- return false;
- }
-
- return true;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof EventRecurrence)) {
- return false;
- }
-
- EventRecurrence er = (EventRecurrence) obj;
- return (startDate == null ?
- er.startDate == null : Time.compare(startDate, er.startDate) == 0) &&
- freq == er.freq &&
- (until == null ? er.until == null : until.equals(er.until)) &&
- count == er.count &&
- interval == er.interval &&
- wkst == er.wkst &&
- arraysEqual(bysecond, bysecondCount, er.bysecond, er.bysecondCount) &&
- arraysEqual(byminute, byminuteCount, er.byminute, er.byminuteCount) &&
- arraysEqual(byhour, byhourCount, er.byhour, er.byhourCount) &&
- arraysEqual(byday, bydayCount, er.byday, er.bydayCount) &&
- arraysEqual(bydayNum, bydayCount, er.bydayNum, er.bydayCount) &&
- arraysEqual(bymonthday, bymonthdayCount, er.bymonthday, er.bymonthdayCount) &&
- arraysEqual(byyearday, byyeardayCount, er.byyearday, er.byyeardayCount) &&
- arraysEqual(byweekno, byweeknoCount, er.byweekno, er.byweeknoCount) &&
- arraysEqual(bymonth, bymonthCount, er.bymonth, er.bymonthCount) &&
- arraysEqual(bysetpos, bysetposCount, er.bysetpos, er.bysetposCount);
- }
-
- @Override public int hashCode() {
- // We overrode equals, so we must override hashCode(). Nobody seems to need this though.
- throw new UnsupportedOperationException();
- }
-
- /**
- * Resets parser-modified fields to their initial state. Does not alter startDate.
- * <p>
- * The original parser always set all of the "count" fields, "wkst", and "until",
- * essentially allowing the same object to be used multiple times by calling parse().
- * It's unclear whether this behavior was intentional. For now, be paranoid and
- * preserve the existing behavior by resetting the fields.
- * <p>
- * We don't need to touch the integer arrays; they will either be ignored or
- * overwritten. The "startDate" field is not set by the parser, so we ignore it here.
- */
- private void resetFields() {
- until = null;
- freq = count = interval = bysecondCount = byminuteCount = byhourCount =
- bydayCount = bymonthdayCount = byyeardayCount = byweeknoCount = bymonthCount =
- bysetposCount = 0;
- }
-
- /**
- * Parses an rfc2445 recurrence rule string into its component pieces. Attempting to parse
- * malformed input will result in an EventRecurrence.InvalidFormatException.
- *
- * @param recur The recurrence rule to parse (in un-folded form).
- */
- public void parse(String recur) {
- /*
- * From RFC 2445 section 4.3.10:
- *
- * recur = "FREQ"=freq *(
- * ; either UNTIL or COUNT may appear in a 'recur',
- * ; but UNTIL and COUNT MUST NOT occur in the same 'recur'
- *
- * ( ";" "UNTIL" "=" enddate ) /
- * ( ";" "COUNT" "=" 1*DIGIT ) /
- *
- * ; the rest of these keywords are optional,
- * ; but MUST NOT occur more than once
- *
- * ( ";" "INTERVAL" "=" 1*DIGIT ) /
- * ( ";" "BYSECOND" "=" byseclist ) /
- * ( ";" "BYMINUTE" "=" byminlist ) /
- * ( ";" "BYHOUR" "=" byhrlist ) /
- * ( ";" "BYDAY" "=" bywdaylist ) /
- * ( ";" "BYMONTHDAY" "=" bymodaylist ) /
- * ( ";" "BYYEARDAY" "=" byyrdaylist ) /
- * ( ";" "BYWEEKNO" "=" bywknolist ) /
- * ( ";" "BYMONTH" "=" bymolist ) /
- * ( ";" "BYSETPOS" "=" bysplist ) /
- * ( ";" "WKST" "=" weekday ) /
- * ( ";" x-name "=" text )
- * )
- *
- * Examples:
- * FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU
- * FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8
- *
- * Strategy:
- * (1) Split the string at ';' boundaries to get an array of rule "parts".
- * (2) For each part, find substrings for left/right sides of '=' (name/value).
- * (3) Call a <name>-specific parsing function to parse the <value> into an
- * output field.
- *
- * By keeping track of which names we've seen in a bit vector, we can verify the
- * constraints indicated above (FREQ appears first, none of them appear more than once --
- * though x-[name] would require special treatment), and we have either UNTIL or COUNT
- * but not both.
- *
- * In general, RFC 2445 property names (e.g. "FREQ") and enumerations ("TU") must
- * be handled in a case-insensitive fashion, but case may be significant for other
- * properties. We don't have any case-sensitive values in RRULE, except possibly
- * for the custom "X-" properties, but we ignore those anyway. Thus, we can trivially
- * convert the entire string to upper case and then use simple comparisons.
- *
- * Differences from previous version:
- * - allows lower-case property and enumeration values [optional]
- * - enforces that FREQ appears first
- * - enforces that only one of UNTIL and COUNT may be specified
- * - allows (but ignores) X-* parts
- * - improved validation on various values (e.g. UNTIL timestamps)
- * - error messages are more specific
- */
-
- /* TODO: replace with "if (freq != 0) throw" if nothing requires this */
- resetFields();
-
- int parseFlags = 0;
- String[] parts;
- if (ALLOW_LOWER_CASE) {
- parts = recur.toUpperCase().split(";");
- } else {
- parts = recur.split(";");
- }
- for (String part : parts) {
- int equalIndex = part.indexOf('=');
- if (equalIndex <= 0) {
- /* no '=' or no LHS */
- throw new InvalidFormatException("Missing LHS in " + part);
- }
-
- String lhs = part.substring(0, equalIndex);
- String rhs = part.substring(equalIndex + 1);
- if (rhs.length() == 0) {
- throw new InvalidFormatException("Missing RHS in " + part);
- }
-
- /*
- * In lieu of a "switch" statement that allows string arguments, we use a
- * map from strings to parsing functions.
- */
- PartParser parser = sParsePartMap.get(lhs);
- if (parser == null) {
- if (lhs.startsWith("X-")) {
- //Log.d(TAG, "Ignoring custom part " + lhs);
- continue;
- }
- throw new InvalidFormatException("Couldn't find parser for " + lhs);
- } else {
- int flag = parser.parsePart(rhs, this);
- if ((parseFlags & flag) != 0) {
- throw new InvalidFormatException("Part " + lhs + " was specified twice");
- }
- if (parseFlags == 0 && flag != PARSED_FREQ) {
- throw new InvalidFormatException("FREQ must be specified first");
- }
- parseFlags |= flag;
- }
- }
-
- // If not specified, week starts on Monday.
- if ((parseFlags & PARSED_WKST) == 0) {
- wkst = MO;
- }
-
- // FREQ is mandatory.
- if ((parseFlags & PARSED_FREQ) == 0) {
- throw new InvalidFormatException("Must specify a FREQ value");
- }
-
- // Can't have both UNTIL and COUNT.
- if ((parseFlags & (PARSED_UNTIL | PARSED_COUNT)) == (PARSED_UNTIL | PARSED_COUNT)) {
- if (ONLY_ONE_UNTIL_COUNT) {
- throw new InvalidFormatException("Must not specify both UNTIL and COUNT: " + recur);
- } else {
- Log.w(TAG, "Warning: rrule has both UNTIL and COUNT: " + recur);
- }
- }
- }
-
- /**
- * Base class for the RRULE part parsers.
- */
- abstract static class PartParser {
- /**
- * Parses a single part.
- *
- * @param value The right-hand-side of the part.
- * @param er The EventRecurrence into which the result is stored.
- * @return A bit value indicating which part was parsed.
- */
- public abstract int parsePart(String value, EventRecurrence er);
-
- /**
- * Parses an integer, with range-checking.
- *
- * @param str The string to parse.
- * @param minVal Minimum allowed value.
- * @param maxVal Maximum allowed value.
- * @param allowZero Is 0 allowed?
- * @return The parsed value.
- */
- public static int parseIntRange(String str, int minVal, int maxVal, boolean allowZero) {
- try {
- if (str.charAt(0) == '+') {
- // Integer.parseInt does not allow a leading '+', so skip it manually.
- str = str.substring(1);
- }
- int val = Integer.parseInt(str);
- if (val < minVal || val > maxVal || (val == 0 && !allowZero)) {
- throw new InvalidFormatException("Integer value out of range: " + str);
- }
- return val;
- } catch (NumberFormatException nfe) {
- throw new InvalidFormatException("Invalid integer value: " + str);
- }
- }
-
- /**
- * Parses a comma-separated list of integers, with range-checking.
- *
- * @param listStr The string to parse.
- * @param minVal Minimum allowed value.
- * @param maxVal Maximum allowed value.
- * @param allowZero Is 0 allowed?
- * @return A new array with values, sized to hold the exact number of elements.
- */
- public static int[] parseNumberList(String listStr, int minVal, int maxVal,
- boolean allowZero) {
- int[] values;
-
- if (listStr.indexOf(",") < 0) {
- // Common case: only one entry, skip split() overhead.
- values = new int[1];
- values[0] = parseIntRange(listStr, minVal, maxVal, allowZero);
- } else {
- String[] valueStrs = listStr.split(",");
- int len = valueStrs.length;
- values = new int[len];
- for (int i = 0; i < len; i++) {
- values[i] = parseIntRange(valueStrs[i], minVal, maxVal, allowZero);
- }
- }
- return values;
- }
- }
-
- /** parses FREQ={SECONDLY,MINUTELY,...} */
- private static class ParseFreq extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- Integer freq = sParseFreqMap.get(value);
- if (freq == null) {
- throw new InvalidFormatException("Invalid FREQ value: " + value);
- }
- er.freq = freq;
- return PARSED_FREQ;
- }
- }
- /** parses UNTIL=enddate, e.g. "19970829T021400" */
- private static class ParseUntil extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- if (VALIDATE_UNTIL) {
- try {
- // Parse the time to validate it. The result isn't retained.
- Time until = new Time();
- until.parse(value);
- } catch (TimeFormatException tfe) {
- throw new InvalidFormatException("Invalid UNTIL value: " + value);
- }
- }
- er.until = value;
- return PARSED_UNTIL;
- }
- }
- /** parses COUNT=[non-negative-integer] */
- private static class ParseCount extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- er.count = parseIntRange(value, 0, Integer.MAX_VALUE, true);
- return PARSED_COUNT;
- }
- }
- /** parses INTERVAL=[non-negative-integer] */
- private static class ParseInterval extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- er.interval = parseIntRange(value, 1, Integer.MAX_VALUE, false);
- return PARSED_INTERVAL;
- }
- }
- /** parses BYSECOND=byseclist */
- private static class ParseBySecond extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] bysecond = parseNumberList(value, 0, 59, true);
- er.bysecond = bysecond;
- er.bysecondCount = bysecond.length;
- return PARSED_BYSECOND;
- }
- }
- /** parses BYMINUTE=byminlist */
- private static class ParseByMinute extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] byminute = parseNumberList(value, 0, 59, true);
- er.byminute = byminute;
- er.byminuteCount = byminute.length;
- return PARSED_BYMINUTE;
- }
- }
- /** parses BYHOUR=byhrlist */
- private static class ParseByHour extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] byhour = parseNumberList(value, 0, 23, true);
- er.byhour = byhour;
- er.byhourCount = byhour.length;
- return PARSED_BYHOUR;
- }
- }
- /** parses BYDAY=bywdaylist, e.g. "1SU,-1SU" */
- private static class ParseByDay extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] byday;
- int[] bydayNum;
- int bydayCount;
-
- if (value.indexOf(",") < 0) {
- /* only one entry, skip split() overhead */
- bydayCount = 1;
- byday = new int[1];
- bydayNum = new int[1];
- parseWday(value, byday, bydayNum, 0);
- } else {
- String[] wdays = value.split(",");
- int len = wdays.length;
- bydayCount = len;
- byday = new int[len];
- bydayNum = new int[len];
- for (int i = 0; i < len; i++) {
- parseWday(wdays[i], byday, bydayNum, i);
- }
- }
- er.byday = byday;
- er.bydayNum = bydayNum;
- er.bydayCount = bydayCount;
- return PARSED_BYDAY;
- }
-
- /** parses [int]weekday, putting the pieces into parallel array entries */
- private static void parseWday(String str, int[] byday, int[] bydayNum, int index) {
- int wdayStrStart = str.length() - 2;
- String wdayStr;
-
- if (wdayStrStart > 0) {
- /* number is included; parse it out and advance to weekday */
- String numPart = str.substring(0, wdayStrStart);
- int num = parseIntRange(numPart, -53, 53, false);
- bydayNum[index] = num;
- wdayStr = str.substring(wdayStrStart);
- } else {
- /* just the weekday string */
- wdayStr = str;
- }
- Integer wday = sParseWeekdayMap.get(wdayStr);
- if (wday == null) {
- throw new InvalidFormatException("Invalid BYDAY value: " + str);
- }
- byday[index] = wday;
- }
- }
- /** parses BYMONTHDAY=bymodaylist */
- private static class ParseByMonthDay extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] bymonthday = parseNumberList(value, -31, 31, false);
- er.bymonthday = bymonthday;
- er.bymonthdayCount = bymonthday.length;
- return PARSED_BYMONTHDAY;
- }
- }
- /** parses BYYEARDAY=byyrdaylist */
- private static class ParseByYearDay extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] byyearday = parseNumberList(value, -366, 366, false);
- er.byyearday = byyearday;
- er.byyeardayCount = byyearday.length;
- return PARSED_BYYEARDAY;
- }
- }
- /** parses BYWEEKNO=bywknolist */
- private static class ParseByWeekNo extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] byweekno = parseNumberList(value, -53, 53, false);
- er.byweekno = byweekno;
- er.byweeknoCount = byweekno.length;
- return PARSED_BYWEEKNO;
- }
- }
- /** parses BYMONTH=bymolist */
- private static class ParseByMonth extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] bymonth = parseNumberList(value, 1, 12, false);
- er.bymonth = bymonth;
- er.bymonthCount = bymonth.length;
- return PARSED_BYMONTH;
- }
- }
- /** parses BYSETPOS=bysplist */
- private static class ParseBySetPos extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- int[] bysetpos = parseNumberList(value, Integer.MIN_VALUE, Integer.MAX_VALUE, true);
- er.bysetpos = bysetpos;
- er.bysetposCount = bysetpos.length;
- return PARSED_BYSETPOS;
- }
- }
- /** parses WKST={SU,MO,...} */
- private static class ParseWkst extends PartParser {
- @Override public int parsePart(String value, EventRecurrence er) {
- Integer wkst = sParseWeekdayMap.get(value);
- if (wkst == null) {
- throw new InvalidFormatException("Invalid WKST value: " + value);
- }
- er.wkst = wkst;
- return PARSED_WKST;
- }
- }
-}
diff --git a/core/java/android/pim/ICalendar.java b/core/java/android/pim/ICalendar.java
deleted file mode 100644
index 58c5c63..0000000
--- a/core/java/android/pim/ICalendar.java
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim;
-
-import android.util.Log;
-
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.ArrayList;
-
-/**
- * Parses RFC 2445 iCalendar objects.
- */
-public class ICalendar {
-
- private static final String TAG = "Sync";
-
- // TODO: keep track of VEVENT, VTODO, VJOURNAL, VFREEBUSY, VTIMEZONE, VALARM
- // components, by type field or by subclass? subclass would allow us to
- // enforce grammars.
-
- /**
- * Exception thrown when an iCalendar object has invalid syntax.
- */
- public static class FormatException extends Exception {
- public FormatException() {
- super();
- }
-
- public FormatException(String msg) {
- super(msg);
- }
-
- public FormatException(String msg, Throwable cause) {
- super(msg, cause);
- }
- }
-
- /**
- * A component within an iCalendar (VEVENT, VTODO, VJOURNAL, VFEEBUSY,
- * VTIMEZONE, VALARM).
- */
- public static class Component {
-
- // components
- private static final String BEGIN = "BEGIN";
- private static final String END = "END";
- private static final String NEWLINE = "\n";
- public static final String VCALENDAR = "VCALENDAR";
- public static final String VEVENT = "VEVENT";
- public static final String VTODO = "VTODO";
- public static final String VJOURNAL = "VJOURNAL";
- public static final String VFREEBUSY = "VFREEBUSY";
- public static final String VTIMEZONE = "VTIMEZONE";
- public static final String VALARM = "VALARM";
-
- private final String mName;
- private final Component mParent; // see if we can get rid of this
- private LinkedList<Component> mChildren = null;
- private final LinkedHashMap<String, ArrayList<Property>> mPropsMap =
- new LinkedHashMap<String, ArrayList<Property>>();
-
- /**
- * Creates a new component with the provided name.
- * @param name The name of the component.
- */
- public Component(String name, Component parent) {
- mName = name;
- mParent = parent;
- }
-
- /**
- * Returns the name of the component.
- * @return The name of the component.
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Returns the parent of this component.
- * @return The parent of this component.
- */
- public Component getParent() {
- return mParent;
- }
-
- /**
- * Helper that lazily gets/creates the list of children.
- * @return The list of children.
- */
- protected LinkedList<Component> getOrCreateChildren() {
- if (mChildren == null) {
- mChildren = new LinkedList<Component>();
- }
- return mChildren;
- }
-
- /**
- * Adds a child component to this component.
- * @param child The child component.
- */
- public void addChild(Component child) {
- getOrCreateChildren().add(child);
- }
-
- /**
- * Returns a list of the Component children of this component. May be
- * null, if there are no children.
- *
- * @return A list of the children.
- */
- public List<Component> getComponents() {
- return mChildren;
- }
-
- /**
- * Adds a Property to this component.
- * @param prop
- */
- public void addProperty(Property prop) {
- String name= prop.getName();
- ArrayList<Property> props = mPropsMap.get(name);
- if (props == null) {
- props = new ArrayList<Property>();
- mPropsMap.put(name, props);
- }
- props.add(prop);
- }
-
- /**
- * Returns a set of the property names within this component.
- * @return A set of property names within this component.
- */
- public Set<String> getPropertyNames() {
- return mPropsMap.keySet();
- }
-
- /**
- * Returns a list of properties with the specified name. Returns null
- * if there are no such properties.
- * @param name The name of the property that should be returned.
- * @return A list of properties with the requested name.
- */
- public List<Property> getProperties(String name) {
- return mPropsMap.get(name);
- }
-
- /**
- * Returns the first property with the specified name. Returns null
- * if there is no such property.
- * @param name The name of the property that should be returned.
- * @return The first property with the specified name.
- */
- public Property getFirstProperty(String name) {
- List<Property> props = mPropsMap.get(name);
- if (props == null || props.size() == 0) {
- return null;
- }
- return props.get(0);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(sb);
- sb.append(NEWLINE);
- return sb.toString();
- }
-
- /**
- * Helper method that appends this component to a StringBuilder. The
- * caller is responsible for appending a newline at the end of the
- * component.
- */
- public void toString(StringBuilder sb) {
- sb.append(BEGIN);
- sb.append(":");
- sb.append(mName);
- sb.append(NEWLINE);
-
- // append the properties
- for (String propertyName : getPropertyNames()) {
- for (Property property : getProperties(propertyName)) {
- property.toString(sb);
- sb.append(NEWLINE);
- }
- }
-
- // append the sub-components
- if (mChildren != null) {
- for (Component component : mChildren) {
- component.toString(sb);
- sb.append(NEWLINE);
- }
- }
-
- sb.append(END);
- sb.append(":");
- sb.append(mName);
- }
- }
-
- /**
- * A property within an iCalendar component (e.g., DTSTART, DTEND, etc.,
- * within a VEVENT).
- */
- public static class Property {
- // properties
- // TODO: do we want to list these here? the complete list is long.
- public static final String DTSTART = "DTSTART";
- public static final String DTEND = "DTEND";
- public static final String DURATION = "DURATION";
- public static final String RRULE = "RRULE";
- public static final String RDATE = "RDATE";
- public static final String EXRULE = "EXRULE";
- public static final String EXDATE = "EXDATE";
- // ... need to add more.
-
- private final String mName;
- private LinkedHashMap<String, ArrayList<Parameter>> mParamsMap =
- new LinkedHashMap<String, ArrayList<Parameter>>();
- private String mValue; // TODO: make this final?
-
- /**
- * Creates a new property with the provided name.
- * @param name The name of the property.
- */
- public Property(String name) {
- mName = name;
- }
-
- /**
- * Creates a new property with the provided name and value.
- * @param name The name of the property.
- * @param value The value of the property.
- */
- public Property(String name, String value) {
- mName = name;
- mValue = value;
- }
-
- /**
- * Returns the name of the property.
- * @return The name of the property.
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Returns the value of this property.
- * @return The value of this property.
- */
- public String getValue() {
- return mValue;
- }
-
- /**
- * Sets the value of this property.
- * @param value The desired value for this property.
- */
- public void setValue(String value) {
- mValue = value;
- }
-
- /**
- * Adds a {@link Parameter} to this property.
- * @param param The parameter that should be added.
- */
- public void addParameter(Parameter param) {
- ArrayList<Parameter> params = mParamsMap.get(param.name);
- if (params == null) {
- params = new ArrayList<Parameter>();
- mParamsMap.put(param.name, params);
- }
- params.add(param);
- }
-
- /**
- * Returns the set of parameter names for this property.
- * @return The set of parameter names for this property.
- */
- public Set<String> getParameterNames() {
- return mParamsMap.keySet();
- }
-
- /**
- * Returns the list of parameters with the specified name. May return
- * null if there are no such parameters.
- * @param name The name of the parameters that should be returned.
- * @return The list of parameters with the specified name.
- */
- public List<Parameter> getParameters(String name) {
- return mParamsMap.get(name);
- }
-
- /**
- * Returns the first parameter with the specified name. May return
- * nll if there is no such parameter.
- * @param name The name of the parameter that should be returned.
- * @return The first parameter with the specified name.
- */
- public Parameter getFirstParameter(String name) {
- ArrayList<Parameter> params = mParamsMap.get(name);
- if (params == null || params.size() == 0) {
- return null;
- }
- return params.get(0);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(sb);
- return sb.toString();
- }
-
- /**
- * Helper method that appends this property to a StringBuilder. The
- * caller is responsible for appending a newline after this property.
- */
- public void toString(StringBuilder sb) {
- sb.append(mName);
- Set<String> parameterNames = getParameterNames();
- for (String parameterName : parameterNames) {
- for (Parameter param : getParameters(parameterName)) {
- sb.append(";");
- param.toString(sb);
- }
- }
- sb.append(":");
- sb.append(mValue);
- }
- }
-
- /**
- * A parameter defined for an iCalendar property.
- */
- // TODO: make this a proper class rather than a struct?
- public static class Parameter {
- public String name;
- public String value;
-
- /**
- * Creates a new empty parameter.
- */
- public Parameter() {
- }
-
- /**
- * Creates a new parameter with the specified name and value.
- * @param name The name of the parameter.
- * @param value The value of the parameter.
- */
- public Parameter(String name, String value) {
- this.name = name;
- this.value = value;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(sb);
- return sb.toString();
- }
-
- /**
- * Helper method that appends this parameter to a StringBuilder.
- */
- public void toString(StringBuilder sb) {
- sb.append(name);
- sb.append("=");
- sb.append(value);
- }
- }
-
- private static final class ParserState {
- // public int lineNumber = 0;
- public String line; // TODO: just point to original text
- public int index;
- }
-
- // use factory method
- private ICalendar() {
- }
-
- // TODO: get rid of this -- handle all of the parsing in one pass through
- // the text.
- private static String normalizeText(String text) {
- // it's supposed to be \r\n, but not everyone does that
- text = text.replaceAll("\r\n", "\n");
- text = text.replaceAll("\r", "\n");
-
- // we deal with line folding, by replacing all "\n " strings
- // with nothing. The RFC specifies "\r\n " to be folded, but
- // we handle "\n " and "\r " too because we can get those.
- text = text.replaceAll("\n ", "");
-
- return text;
- }
-
- /**
- * Parses text into an iCalendar component. Parses into the provided
- * component, if not null, or parses into a new component. In the latter
- * case, expects a BEGIN as the first line. Returns the provided or newly
- * created top-level component.
- */
- // TODO: use an index into the text, so we can make this a recursive
- // function?
- private static Component parseComponentImpl(Component component,
- String text)
- throws FormatException {
- Component current = component;
- ParserState state = new ParserState();
- state.index = 0;
-
- // split into lines
- String[] lines = text.split("\n");
-
- // each line is of the format:
- // name *(";" param) ":" value
- for (String line : lines) {
- try {
- current = parseLine(line, state, current);
- // if the provided component was null, we will return the root
- // NOTE: in this case, if the first line is not a BEGIN, a
- // FormatException will get thrown.
- if (component == null) {
- component = current;
- }
- } catch (FormatException fe) {
- if (false) {
- Log.v(TAG, "Cannot parse " + line, fe);
- }
- // for now, we ignore the parse error. Google Calendar seems
- // to be emitting some misformatted iCalendar objects.
- }
- continue;
- }
- return component;
- }
-
- /**
- * Parses a line into the provided component. Creates a new component if
- * the line is a BEGIN, adding the newly created component to the provided
- * parent. Returns whatever component is the current one (to which new
- * properties will be added) in the parse.
- */
- private static Component parseLine(String line, ParserState state,
- Component component)
- throws FormatException {
- state.line = line;
- int len = state.line.length();
-
- // grab the name
- char c = 0;
- for (state.index = 0; state.index < len; ++state.index) {
- c = line.charAt(state.index);
- if (c == ';' || c == ':') {
- break;
- }
- }
- String name = line.substring(0, state.index);
-
- if (component == null) {
- if (!Component.BEGIN.equals(name)) {
- throw new FormatException("Expected BEGIN");
- }
- }
-
- Property property;
- if (Component.BEGIN.equals(name)) {
- // start a new component
- String componentName = extractValue(state);
- Component child = new Component(componentName, component);
- if (component != null) {
- component.addChild(child);
- }
- return child;
- } else if (Component.END.equals(name)) {
- // finish the current component
- String componentName = extractValue(state);
- if (component == null ||
- !componentName.equals(component.getName())) {
- throw new FormatException("Unexpected END " + componentName);
- }
- return component.getParent();
- } else {
- property = new Property(name);
- }
-
- if (c == ';') {
- Parameter parameter = null;
- while ((parameter = extractParameter(state)) != null) {
- property.addParameter(parameter);
- }
- }
- String value = extractValue(state);
- property.setValue(value);
- component.addProperty(property);
- return component;
- }
-
- /**
- * Extracts the value ":..." on the current line. The first character must
- * be a ':'.
- */
- private static String extractValue(ParserState state)
- throws FormatException {
- String line = state.line;
- if (state.index >= line.length() || line.charAt(state.index) != ':') {
- throw new FormatException("Expected ':' before end of line in "
- + line);
- }
- String value = line.substring(state.index + 1);
- state.index = line.length() - 1;
- return value;
- }
-
- /**
- * Extracts the next parameter from the line, if any. If there are no more
- * parameters, returns null.
- */
- private static Parameter extractParameter(ParserState state)
- throws FormatException {
- String text = state.line;
- int len = text.length();
- Parameter parameter = null;
- int startIndex = -1;
- int equalIndex = -1;
- while (state.index < len) {
- char c = text.charAt(state.index);
- if (c == ':') {
- if (parameter != null) {
- if (equalIndex == -1) {
- throw new FormatException("Expected '=' within "
- + "parameter in " + text);
- }
- parameter.value = text.substring(equalIndex + 1,
- state.index);
- }
- return parameter; // may be null
- } else if (c == ';') {
- if (parameter != null) {
- if (equalIndex == -1) {
- throw new FormatException("Expected '=' within "
- + "parameter in " + text);
- }
- parameter.value = text.substring(equalIndex + 1,
- state.index);
- return parameter;
- } else {
- parameter = new Parameter();
- startIndex = state.index;
- }
- } else if (c == '=') {
- equalIndex = state.index;
- if ((parameter == null) || (startIndex == -1)) {
- throw new FormatException("Expected ';' before '=' in "
- + text);
- }
- parameter.name = text.substring(startIndex + 1, equalIndex);
- } else if (c == '"') {
- if (parameter == null) {
- throw new FormatException("Expected parameter before '\"' in " + text);
- }
- if (equalIndex == -1) {
- throw new FormatException("Expected '=' within parameter in " + text);
- }
- if (state.index > equalIndex + 1) {
- throw new FormatException("Parameter value cannot contain a '\"' in " + text);
- }
- final int endQuote = text.indexOf('"', state.index + 1);
- if (endQuote < 0) {
- throw new FormatException("Expected closing '\"' in " + text);
- }
- parameter.value = text.substring(state.index + 1, endQuote);
- state.index = endQuote + 1;
- return parameter;
- }
- ++state.index;
- }
- throw new FormatException("Expected ':' before end of line in " + text);
- }
-
- /**
- * Parses the provided text into an iCalendar object. The top-level
- * component must be of type VCALENDAR.
- * @param text The text to be parsed.
- * @return The top-level VCALENDAR component.
- * @throws FormatException Thrown if the text could not be parsed into an
- * iCalendar VCALENDAR object.
- */
- public static Component parseCalendar(String text) throws FormatException {
- Component calendar = parseComponent(null, text);
- if (calendar == null || !Component.VCALENDAR.equals(calendar.getName())) {
- throw new FormatException("Expected " + Component.VCALENDAR);
- }
- return calendar;
- }
-
- /**
- * Parses the provided text into an iCalendar event. The top-level
- * component must be of type VEVENT.
- * @param text The text to be parsed.
- * @return The top-level VEVENT component.
- * @throws FormatException Thrown if the text could not be parsed into an
- * iCalendar VEVENT.
- */
- public static Component parseEvent(String text) throws FormatException {
- Component event = parseComponent(null, text);
- if (event == null || !Component.VEVENT.equals(event.getName())) {
- throw new FormatException("Expected " + Component.VEVENT);
- }
- return event;
- }
-
- /**
- * Parses the provided text into an iCalendar component.
- * @param text The text to be parsed.
- * @return The top-level component.
- * @throws FormatException Thrown if the text could not be parsed into an
- * iCalendar component.
- */
- public static Component parseComponent(String text) throws FormatException {
- return parseComponent(null, text);
- }
-
- /**
- * Parses the provided text, adding to the provided component.
- * @param component The component to which the parsed iCalendar data should
- * be added.
- * @param text The text to be parsed.
- * @return The top-level component.
- * @throws FormatException Thrown if the text could not be parsed as an
- * iCalendar object.
- */
- public static Component parseComponent(Component component, String text)
- throws FormatException {
- text = normalizeText(text);
- return parseComponentImpl(component, text);
- }
-}
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
deleted file mode 100644
index b7fb320..0000000
--- a/core/java/android/pim/RecurrenceSet.java
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.provider.CalendarContract;
-import android.text.TextUtils;
-import android.text.format.Time;
-import android.util.Log;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * Basic information about a recurrence, following RFC 2445 Section 4.8.5.
- * Contains the RRULEs, RDATE, EXRULEs, and EXDATE properties.
- */
-public class RecurrenceSet {
-
- private final static String TAG = "CalendarProvider";
-
- private final static String RULE_SEPARATOR = "\n";
- private final static String FOLDING_SEPARATOR = "\n ";
-
- // TODO: make these final?
- public EventRecurrence[] rrules = null;
- public long[] rdates = null;
- public EventRecurrence[] exrules = null;
- public long[] exdates = null;
-
- /**
- * Creates a new RecurrenceSet from information stored in the
- * events table in the CalendarProvider.
- * @param values The values retrieved from the Events table.
- */
- public RecurrenceSet(ContentValues values)
- throws EventRecurrence.InvalidFormatException {
- String rruleStr = values.getAsString(CalendarContract.Events.RRULE);
- String rdateStr = values.getAsString(CalendarContract.Events.RDATE);
- String exruleStr = values.getAsString(CalendarContract.Events.EXRULE);
- String exdateStr = values.getAsString(CalendarContract.Events.EXDATE);
- init(rruleStr, rdateStr, exruleStr, exdateStr);
- }
-
- /**
- * Creates a new RecurrenceSet from information stored in a database
- * {@link Cursor} pointing to the events table in the
- * CalendarProvider. The cursor must contain the RRULE, RDATE, EXRULE,
- * and EXDATE columns.
- *
- * @param cursor The cursor containing the RRULE, RDATE, EXRULE, and EXDATE
- * columns.
- */
- public RecurrenceSet(Cursor cursor)
- throws EventRecurrence.InvalidFormatException {
- int rruleColumn = cursor.getColumnIndex(CalendarContract.Events.RRULE);
- int rdateColumn = cursor.getColumnIndex(CalendarContract.Events.RDATE);
- int exruleColumn = cursor.getColumnIndex(CalendarContract.Events.EXRULE);
- int exdateColumn = cursor.getColumnIndex(CalendarContract.Events.EXDATE);
- String rruleStr = cursor.getString(rruleColumn);
- String rdateStr = cursor.getString(rdateColumn);
- String exruleStr = cursor.getString(exruleColumn);
- String exdateStr = cursor.getString(exdateColumn);
- init(rruleStr, rdateStr, exruleStr, exdateStr);
- }
-
- public RecurrenceSet(String rruleStr, String rdateStr,
- String exruleStr, String exdateStr)
- throws EventRecurrence.InvalidFormatException {
- init(rruleStr, rdateStr, exruleStr, exdateStr);
- }
-
- private void init(String rruleStr, String rdateStr,
- String exruleStr, String exdateStr)
- throws EventRecurrence.InvalidFormatException {
- if (!TextUtils.isEmpty(rruleStr) || !TextUtils.isEmpty(rdateStr)) {
-
- if (!TextUtils.isEmpty(rruleStr)) {
- String[] rruleStrs = rruleStr.split(RULE_SEPARATOR);
- rrules = new EventRecurrence[rruleStrs.length];
- for (int i = 0; i < rruleStrs.length; ++i) {
- EventRecurrence rrule = new EventRecurrence();
- rrule.parse(rruleStrs[i]);
- rrules[i] = rrule;
- }
- }
-
- if (!TextUtils.isEmpty(rdateStr)) {
- rdates = parseRecurrenceDates(rdateStr);
- }
-
- if (!TextUtils.isEmpty(exruleStr)) {
- String[] exruleStrs = exruleStr.split(RULE_SEPARATOR);
- exrules = new EventRecurrence[exruleStrs.length];
- for (int i = 0; i < exruleStrs.length; ++i) {
- EventRecurrence exrule = new EventRecurrence();
- exrule.parse(exruleStr);
- exrules[i] = exrule;
- }
- }
-
- if (!TextUtils.isEmpty(exdateStr)) {
- exdates = parseRecurrenceDates(exdateStr);
- }
- }
- }
-
- /**
- * Returns whether or not a recurrence is defined in this RecurrenceSet.
- * @return Whether or not a recurrence is defined in this RecurrenceSet.
- */
- public boolean hasRecurrence() {
- return (rrules != null || rdates != null);
- }
-
- /**
- * Parses the provided RDATE or EXDATE string into an array of longs
- * representing each date/time in the recurrence.
- * @param recurrence The recurrence to be parsed.
- * @return The list of date/times.
- */
- public static long[] parseRecurrenceDates(String recurrence) {
- // TODO: use "local" time as the default. will need to handle times
- // that end in "z" (UTC time) explicitly at that point.
- String tz = Time.TIMEZONE_UTC;
- int tzidx = recurrence.indexOf(";");
- if (tzidx != -1) {
- tz = recurrence.substring(0, tzidx);
- recurrence = recurrence.substring(tzidx + 1);
- }
- Time time = new Time(tz);
- String[] rawDates = recurrence.split(",");
- int n = rawDates.length;
- long[] dates = new long[n];
- for (int i = 0; i<n; ++i) {
- // The timezone is updated to UTC if the time string specified 'Z'.
- time.parse(rawDates[i]);
- dates[i] = time.toMillis(false /* use isDst */);
- time.timezone = tz;
- }
- return dates;
- }
-
- /**
- * Populates the database map of values with the appropriate RRULE, RDATE,
- * EXRULE, and EXDATE values extracted from the parsed iCalendar component.
- * @param component The iCalendar component containing the desired
- * recurrence specification.
- * @param values The db values that should be updated.
- * @return true if the component contained the necessary information
- * to specify a recurrence. The required fields are DTSTART,
- * one of DTEND/DURATION, and one of RRULE/RDATE. Returns false if
- * there was an error, including if the date is out of range.
- */
- public static boolean populateContentValues(ICalendar.Component component,
- ContentValues values) {
- ICalendar.Property dtstartProperty =
- component.getFirstProperty("DTSTART");
- String dtstart = dtstartProperty.getValue();
- ICalendar.Parameter tzidParam =
- dtstartProperty.getFirstParameter("TZID");
- // NOTE: the timezone may be null, if this is a floating time.
- String tzid = tzidParam == null ? null : tzidParam.value;
- Time start = new Time(tzidParam == null ? Time.TIMEZONE_UTC : tzid);
- boolean inUtc = start.parse(dtstart);
- boolean allDay = start.allDay;
-
- // We force TimeZone to UTC for "all day recurring events" as the server is sending no
- // TimeZone in DTSTART for them
- if (inUtc || allDay) {
- tzid = Time.TIMEZONE_UTC;
- }
-
- String duration = computeDuration(start, component);
- String rrule = flattenProperties(component, "RRULE");
- String rdate = extractDates(component.getFirstProperty("RDATE"));
- String exrule = flattenProperties(component, "EXRULE");
- String exdate = extractDates(component.getFirstProperty("EXDATE"));
-
- if ((TextUtils.isEmpty(dtstart))||
- (TextUtils.isEmpty(duration))||
- ((TextUtils.isEmpty(rrule))&&
- (TextUtils.isEmpty(rdate)))) {
- if (false) {
- Log.d(TAG, "Recurrence missing DTSTART, DTEND/DURATION, "
- + "or RRULE/RDATE: "
- + component.toString());
- }
- return false;
- }
-
- if (allDay) {
- start.timezone = Time.TIMEZONE_UTC;
- }
- long millis = start.toMillis(false /* use isDst */);
- values.put(CalendarContract.Events.DTSTART, millis);
- if (millis == -1) {
- if (false) {
- Log.d(TAG, "DTSTART is out of range: " + component.toString());
- }
- return false;
- }
-
- values.put(CalendarContract.Events.RRULE, rrule);
- values.put(CalendarContract.Events.RDATE, rdate);
- values.put(CalendarContract.Events.EXRULE, exrule);
- values.put(CalendarContract.Events.EXDATE, exdate);
- values.put(CalendarContract.Events.EVENT_TIMEZONE, tzid);
- values.put(CalendarContract.Events.DURATION, duration);
- values.put(CalendarContract.Events.ALL_DAY, allDay ? 1 : 0);
- return true;
- }
-
- // This can be removed when the old CalendarSyncAdapter is removed.
- public static boolean populateComponent(Cursor cursor,
- ICalendar.Component component) {
-
- int dtstartColumn = cursor.getColumnIndex(CalendarContract.Events.DTSTART);
- int durationColumn = cursor.getColumnIndex(CalendarContract.Events.DURATION);
- int tzidColumn = cursor.getColumnIndex(CalendarContract.Events.EVENT_TIMEZONE);
- int rruleColumn = cursor.getColumnIndex(CalendarContract.Events.RRULE);
- int rdateColumn = cursor.getColumnIndex(CalendarContract.Events.RDATE);
- int exruleColumn = cursor.getColumnIndex(CalendarContract.Events.EXRULE);
- int exdateColumn = cursor.getColumnIndex(CalendarContract.Events.EXDATE);
- int allDayColumn = cursor.getColumnIndex(CalendarContract.Events.ALL_DAY);
-
-
- long dtstart = -1;
- if (!cursor.isNull(dtstartColumn)) {
- dtstart = cursor.getLong(dtstartColumn);
- }
- String duration = cursor.getString(durationColumn);
- String tzid = cursor.getString(tzidColumn);
- String rruleStr = cursor.getString(rruleColumn);
- String rdateStr = cursor.getString(rdateColumn);
- String exruleStr = cursor.getString(exruleColumn);
- String exdateStr = cursor.getString(exdateColumn);
- boolean allDay = cursor.getInt(allDayColumn) == 1;
-
- if ((dtstart == -1) ||
- (TextUtils.isEmpty(duration))||
- ((TextUtils.isEmpty(rruleStr))&&
- (TextUtils.isEmpty(rdateStr)))) {
- // no recurrence.
- return false;
- }
-
- ICalendar.Property dtstartProp = new ICalendar.Property("DTSTART");
- Time dtstartTime = null;
- if (!TextUtils.isEmpty(tzid)) {
- if (!allDay) {
- dtstartProp.addParameter(new ICalendar.Parameter("TZID", tzid));
- }
- dtstartTime = new Time(tzid);
- } else {
- // use the "floating" timezone
- dtstartTime = new Time(Time.TIMEZONE_UTC);
- }
-
- dtstartTime.set(dtstart);
- // make sure the time is printed just as a date, if all day.
- // TODO: android.pim.Time really should take care of this for us.
- if (allDay) {
- dtstartProp.addParameter(new ICalendar.Parameter("VALUE", "DATE"));
- dtstartTime.allDay = true;
- dtstartTime.hour = 0;
- dtstartTime.minute = 0;
- dtstartTime.second = 0;
- }
-
- dtstartProp.setValue(dtstartTime.format2445());
- component.addProperty(dtstartProp);
- ICalendar.Property durationProp = new ICalendar.Property("DURATION");
- durationProp.setValue(duration);
- component.addProperty(durationProp);
-
- addPropertiesForRuleStr(component, "RRULE", rruleStr);
- addPropertyForDateStr(component, "RDATE", rdateStr);
- addPropertiesForRuleStr(component, "EXRULE", exruleStr);
- addPropertyForDateStr(component, "EXDATE", exdateStr);
- return true;
- }
-
-public static boolean populateComponent(ContentValues values,
- ICalendar.Component component) {
- long dtstart = -1;
- if (values.containsKey(CalendarContract.Events.DTSTART)) {
- dtstart = values.getAsLong(CalendarContract.Events.DTSTART);
- }
- String duration = values.getAsString(CalendarContract.Events.DURATION);
- String tzid = values.getAsString(CalendarContract.Events.EVENT_TIMEZONE);
- String rruleStr = values.getAsString(CalendarContract.Events.RRULE);
- String rdateStr = values.getAsString(CalendarContract.Events.RDATE);
- String exruleStr = values.getAsString(CalendarContract.Events.EXRULE);
- String exdateStr = values.getAsString(CalendarContract.Events.EXDATE);
- Integer allDayInteger = values.getAsInteger(CalendarContract.Events.ALL_DAY);
- boolean allDay = (null != allDayInteger) ? (allDayInteger == 1) : false;
-
- if ((dtstart == -1) ||
- (TextUtils.isEmpty(duration))||
- ((TextUtils.isEmpty(rruleStr))&&
- (TextUtils.isEmpty(rdateStr)))) {
- // no recurrence.
- return false;
- }
-
- ICalendar.Property dtstartProp = new ICalendar.Property("DTSTART");
- Time dtstartTime = null;
- if (!TextUtils.isEmpty(tzid)) {
- if (!allDay) {
- dtstartProp.addParameter(new ICalendar.Parameter("TZID", tzid));
- }
- dtstartTime = new Time(tzid);
- } else {
- // use the "floating" timezone
- dtstartTime = new Time(Time.TIMEZONE_UTC);
- }
-
- dtstartTime.set(dtstart);
- // make sure the time is printed just as a date, if all day.
- // TODO: android.pim.Time really should take care of this for us.
- if (allDay) {
- dtstartProp.addParameter(new ICalendar.Parameter("VALUE", "DATE"));
- dtstartTime.allDay = true;
- dtstartTime.hour = 0;
- dtstartTime.minute = 0;
- dtstartTime.second = 0;
- }
-
- dtstartProp.setValue(dtstartTime.format2445());
- component.addProperty(dtstartProp);
- ICalendar.Property durationProp = new ICalendar.Property("DURATION");
- durationProp.setValue(duration);
- component.addProperty(durationProp);
-
- addPropertiesForRuleStr(component, "RRULE", rruleStr);
- addPropertyForDateStr(component, "RDATE", rdateStr);
- addPropertiesForRuleStr(component, "EXRULE", exruleStr);
- addPropertyForDateStr(component, "EXDATE", exdateStr);
- return true;
- }
-
- private static void addPropertiesForRuleStr(ICalendar.Component component,
- String propertyName,
- String ruleStr) {
- if (TextUtils.isEmpty(ruleStr)) {
- return;
- }
- String[] rrules = getRuleStrings(ruleStr);
- for (String rrule : rrules) {
- ICalendar.Property prop = new ICalendar.Property(propertyName);
- prop.setValue(rrule);
- component.addProperty(prop);
- }
- }
-
- private static String[] getRuleStrings(String ruleStr) {
- if (null == ruleStr) {
- return new String[0];
- }
- String unfoldedRuleStr = unfold(ruleStr);
- String[] split = unfoldedRuleStr.split(RULE_SEPARATOR);
- int count = split.length;
- for (int n = 0; n < count; n++) {
- split[n] = fold(split[n]);
- }
- return split;
- }
-
-
- private static final Pattern IGNORABLE_ICAL_WHITESPACE_RE =
- Pattern.compile("(?:\\r\\n?|\\n)[ \t]");
-
- private static final Pattern FOLD_RE = Pattern.compile(".{75}");
-
- /**
- * fold and unfolds ical content lines as per RFC 2445 section 4.1.
- *
- * <h3>4.1 Content Lines</h3>
- *
- * <p>The iCalendar object is organized into individual lines of text, called
- * content lines. Content lines are delimited by a line break, which is a CRLF
- * sequence (US-ASCII decimal 13, followed by US-ASCII decimal 10).
- *
- * <p>Lines of text SHOULD NOT be longer than 75 octets, excluding the line
- * break. Long content lines SHOULD be split into a multiple line
- * representations using a line "folding" technique. That is, a long line can
- * be split between any two characters by inserting a CRLF immediately
- * followed by a single linear white space character (i.e., SPACE, US-ASCII
- * decimal 32 or HTAB, US-ASCII decimal 9). Any sequence of CRLF followed
- * immediately by a single linear white space character is ignored (i.e.,
- * removed) when processing the content type.
- */
- public static String fold(String unfoldedIcalContent) {
- return FOLD_RE.matcher(unfoldedIcalContent).replaceAll("$0\r\n ");
- }
-
- public static String unfold(String foldedIcalContent) {
- return IGNORABLE_ICAL_WHITESPACE_RE.matcher(
- foldedIcalContent).replaceAll("");
- }
-
- private static void addPropertyForDateStr(ICalendar.Component component,
- String propertyName,
- String dateStr) {
- if (TextUtils.isEmpty(dateStr)) {
- return;
- }
-
- ICalendar.Property prop = new ICalendar.Property(propertyName);
- String tz = null;
- int tzidx = dateStr.indexOf(";");
- if (tzidx != -1) {
- tz = dateStr.substring(0, tzidx);
- dateStr = dateStr.substring(tzidx + 1);
- }
- if (!TextUtils.isEmpty(tz)) {
- prop.addParameter(new ICalendar.Parameter("TZID", tz));
- }
- prop.setValue(dateStr);
- component.addProperty(prop);
- }
-
- private static String computeDuration(Time start,
- ICalendar.Component component) {
- // see if a duration is defined
- ICalendar.Property durationProperty =
- component.getFirstProperty("DURATION");
- if (durationProperty != null) {
- // just return the duration
- return durationProperty.getValue();
- }
-
- // must compute a duration from the DTEND
- ICalendar.Property dtendProperty =
- component.getFirstProperty("DTEND");
- if (dtendProperty == null) {
- // no DURATION, no DTEND: 0 second duration
- return "+P0S";
- }
- ICalendar.Parameter endTzidParameter =
- dtendProperty.getFirstParameter("TZID");
- String endTzid = (endTzidParameter == null)
- ? start.timezone : endTzidParameter.value;
-
- Time end = new Time(endTzid);
- end.parse(dtendProperty.getValue());
- long durationMillis = end.toMillis(false /* use isDst */)
- - start.toMillis(false /* use isDst */);
- long durationSeconds = (durationMillis / 1000);
- if (start.allDay && (durationSeconds % 86400) == 0) {
- return "P" + (durationSeconds / 86400) + "D"; // Server wants this instead of P86400S
- } else {
- return "P" + durationSeconds + "S";
- }
- }
-
- private static String flattenProperties(ICalendar.Component component,
- String name) {
- List<ICalendar.Property> properties = component.getProperties(name);
- if (properties == null || properties.isEmpty()) {
- return null;
- }
-
- if (properties.size() == 1) {
- return properties.get(0).getValue();
- }
-
- StringBuilder sb = new StringBuilder();
-
- boolean first = true;
- for (ICalendar.Property property : component.getProperties(name)) {
- if (first) {
- first = false;
- } else {
- // TODO: use commas. our RECUR parsing should handle that
- // anyway.
- sb.append(RULE_SEPARATOR);
- }
- sb.append(property.getValue());
- }
- return sb.toString();
- }
-
- private static String extractDates(ICalendar.Property recurrence) {
- if (recurrence == null) {
- return null;
- }
- ICalendar.Parameter tzidParam =
- recurrence.getFirstParameter("TZID");
- if (tzidParam != null) {
- return tzidParam.value + ";" + recurrence.getValue();
- }
- return recurrence.getValue();
- }
-}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 61deea4..ec67683 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -135,14 +135,6 @@
public static final String ALLOW_PROFILE = "allow_profile";
/**
- * A query parameter key used to specify the package that is requesting a query.
- * This is used for restricting data based on package name.
- *
- * @hide
- */
- public static final String REQUESTING_PACKAGE_PARAM_KEY = "requesting_package";
-
- /**
* Query parameter that should be used by the client to access a specific
* {@link Directory}. The parameter value should be the _ID of the corresponding
* directory, e.g.
@@ -271,8 +263,6 @@
* <li>The URI authority is replaced with the corresponding {@link #DIRECTORY_AUTHORITY}.</li>
* <li>The {@code accountName=} and {@code accountType=} parameters are added or
* replaced using the corresponding {@link #ACCOUNT_TYPE} and {@link #ACCOUNT_NAME} values.</li>
- * <li>If the URI is missing a ContactsContract.REQUESTING_PACKAGE_PARAM_KEY
- * parameter, this parameter is added.</li>
* </ul>
* </p>
* <p>
@@ -1881,13 +1871,16 @@
public static final String CONTACT_ID = "contact_id";
/**
- * Flag indicating that this {@link RawContacts} entry and its children have
- * been restricted to specific platform apps.
- * <P>Type: INTEGER (boolean)</P>
+ * The data set within the account that this row belongs to. This allows
+ * multiple sync adapters for the same account type to distinguish between
+ * each others' data.
*
- * @hide until finalized in future platform release
+ * This is empty by default, and is completely optional. It only needs to
+ * be populated if multiple sync adapters are entering distinct data for
+ * the same account type and account name.
+ * <P>Type: TEXT</P>
*/
- public static final String IS_RESTRICTED = "is_restricted";
+ public static final String DATA_SET = "data_set";
/**
* The aggregation mode for this contact.
@@ -2211,8 +2204,8 @@
* <td>The name of the account instance to which this row belongs, which when paired with
* {@link #ACCOUNT_TYPE} identifies a specific account.
* For example, this will be the Gmail address if it is a Google account.
- * It should be set at the time
- * the raw contact is inserted and never changed afterwards.</td>
+ * It should be set at the time the raw contact is inserted and never
+ * changed afterwards.</td>
* </tr>
* <tr>
* <td>String</td>
@@ -2222,8 +2215,8 @@
* <p>
* The type of account to which this row belongs, which when paired with
* {@link #ACCOUNT_NAME} identifies a specific account.
- * It should be set at the time
- * the raw contact is inserted and never changed afterwards.
+ * It should be set at the time the raw contact is inserted and never
+ * changed afterwards.
* </p>
* <p>
* To ensure uniqueness, new account types should be chosen according to the
@@ -2233,15 +2226,38 @@
* </tr>
* <tr>
* <td>String</td>
+ * <td>{@link #DATA_SET}</td>
+ * <td>read/write-once</td>
+ * <td>
+ * <p>
+ * The data set within the account that this row belongs to. This allows
+ * multiple sync adapters for the same account type to distinguish between
+ * each others' data. The combination of {@link #ACCOUNT_TYPE},
+ * {@link #ACCOUNT_NAME}, and {@link #DATA_SET} identifies a set of data
+ * that is associated with a single sync adapter.
+ * </p>
+ * <p>
+ * This is empty by default, and is completely optional. It only needs to
+ * be populated if multiple sync adapters are entering distinct data for
+ * the same account type and account name.
+ * </p>
+ * <p>
+ * It should be set at the time the raw contact is inserted and never
+ * changed afterwards.
+ * </p>
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>String</td>
* <td>{@link #SOURCE_ID}</td>
* <td>read/write</td>
* <td>String that uniquely identifies this row to its source account.
* Typically it is set at the time the raw contact is inserted and never
* changed afterwards. The one notable exception is a new raw contact: it
- * will have an account name and type, but no source id. This
- * indicates to the sync adapter that a new contact needs to be created
- * server-side and its ID stored in the corresponding SOURCE_ID field on
- * the phone.
+ * will have an account name and type (and possibly a data set), but no
+ * source id. This indicates to the sync adapter that a new contact needs
+ * to be created server-side and its ID stored in the corresponding
+ * SOURCE_ID field on the phone.
* </td>
* </tr>
* <tr>
@@ -2537,7 +2553,6 @@
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DELETED);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, CONTACT_ID);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, STARRED);
- DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, IS_RESTRICTED);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, NAME_VERIFIED);
android.content.Entity contact = new android.content.Entity(cv);
@@ -3814,27 +3829,6 @@
/**
* <p>
- * If {@link #FOR_EXPORT_ONLY} is explicitly set to "1", returned Cursor toward
- * Data.CONTENT_URI contains only exportable data.
- * </p>
- * <p>
- * This flag is useful (currently) only for vCard exporter in Contacts app, which
- * needs to exclude "un-exportable" data from available data to export, while
- * Contacts app itself has priviledge to access all data including "un-exportable"
- * ones and providers return all of them regardless of the callers' intention.
- * </p>
- * <p>
- * Type: INTEGER
- * </p>
- *
- * @hide Maybe available only in Eclair and not really ready for public use.
- * TODO: remove, or implement this feature completely. As of now (Eclair),
- * we only use this flag in queryEntities(), not query().
- */
- public static final String FOR_EXPORT_ONLY = "for_export_only";
-
- /**
- * <p>
* Build a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
* style {@link Uri} for the parent {@link android.provider.ContactsContract.Contacts}
* entry of the given {@link ContactsContract.Data} entry.
@@ -6213,6 +6207,18 @@
*/
protected interface GroupsColumns {
/**
+ * The data set within the account that this group belongs to. This allows
+ * multiple sync adapters for the same account type to distinguish between
+ * each others' group data.
+ *
+ * This is empty by default, and is completely optional. It only needs to
+ * be populated if multiple sync adapters are entering distinct group data
+ * for the same account type and account name.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DATA_SET = "data_set";
+
+ /**
* The display title of this group.
* <p>
* Type: TEXT
@@ -6338,6 +6344,29 @@
* In other words, it would be a really bad idea to delete and reinsert a
* group. A sync adapter should always do an update instead.</td>
* </tr>
+ # <tr>
+ * <td>String</td>
+ * <td>{@link #DATA_SET}</td>
+ * <td>read/write-once</td>
+ * <td>
+ * <p>
+ * The data set within the account that this group belongs to. This allows
+ * multiple sync adapters for the same account type to distinguish between
+ * each others' group data. The combination of {@link #ACCOUNT_TYPE},
+ * {@link #ACCOUNT_NAME}, and {@link #DATA_SET} identifies a set of data
+ * that is associated with a single sync adapter.
+ * </p>
+ * <p>
+ * This is empty by default, and is completely optional. It only needs to
+ * be populated if multiple sync adapters are entering distinct data for
+ * the same account type and account name.
+ * </p>
+ * <p>
+ * It should be set at the time the group is inserted and never changed
+ * afterwards.
+ * </p>
+ * </td>
+ * </tr>
* <tr>
* <td>String</td>
* <td>{@link #TITLE}</td>
diff --git a/core/java/android/server/BluetoothHealthProfileHandler.java b/core/java/android/server/BluetoothHealthProfileHandler.java
index 7f862e0..105ff332 100644
--- a/core/java/android/server/BluetoothHealthProfileHandler.java
+++ b/core/java/android/server/BluetoothHealthProfileHandler.java
@@ -20,15 +20,12 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHealth;
import android.bluetooth.BluetoothHealthAppConfiguration;
-import android.bluetooth.BluetoothHealth;
-import android.bluetooth.BluetoothInputDevice;
+import android.bluetooth.IBluetoothHealthCallback;
import android.content.Context;
-import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.provider.Settings;
import android.util.Log;
import java.util.ArrayList;
@@ -36,10 +33,6 @@
import java.util.List;
import java.util.Map.Entry;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-
/**
* This handles all the operations on the Bluetooth Health profile.
* All functions are called by BluetoothService, as Bluetooth Service
@@ -58,6 +51,7 @@
private ArrayList<HealthChannel> mHealthChannels;
private HashMap <BluetoothHealthAppConfiguration, String> mHealthAppConfigs;
private HashMap <BluetoothDevice, Integer> mHealthDevices;
+ private HashMap <BluetoothHealthAppConfiguration, IBluetoothHealthCallback> mCallbacks;
private static final int MESSAGE_REGISTER_APPLICATION = 0;
private static final int MESSAGE_UNREGISTER_APPLICATION = 1;
@@ -103,6 +97,7 @@
}
if (path == null) {
+ mCallbacks.remove(registerApp);
callHealthApplicationStatusCallback(registerApp,
BluetoothHealth.APPLICATION_REGISTRATION_FAILURE);
} else {
@@ -118,6 +113,7 @@
boolean result = mBluetoothService.unregisterHealthApplicationNative(
mHealthAppConfigs.get(unregisterApp));
if (result) {
+ mCallbacks.remove(unregisterApp);
callHealthApplicationStatusCallback(unregisterApp,
BluetoothHealth.APPLICATION_UNREGISTRATION_SUCCESS);
} else {
@@ -149,6 +145,7 @@
mHealthAppConfigs = new HashMap<BluetoothHealthAppConfiguration, String>();
mHealthChannels = new ArrayList<HealthChannel>();
mHealthDevices = new HashMap<BluetoothDevice, Integer>();
+ mCallbacks = new HashMap<BluetoothHealthAppConfiguration, IBluetoothHealthCallback>();
}
static synchronized BluetoothHealthProfileHandler getInstance(Context context,
@@ -157,10 +154,12 @@
return sInstance;
}
- boolean registerAppConfiguration(BluetoothHealthAppConfiguration config) {
+ boolean registerAppConfiguration(BluetoothHealthAppConfiguration config,
+ IBluetoothHealthCallback callback) {
Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_APPLICATION);
msg.obj = config;
mHandler.sendMessage(msg);
+ mCallbacks.put(config, callback);
return true;
}
@@ -442,11 +441,11 @@
debugLog("Health Device Callback: " + device + " State Change: "
+ prevState + "->" + state);
- try {
- config.getCallback().onHealthChannelStateChange(config, device, prevState,
- state, fd);
- } catch (RemoteException e) {
- errorLog("Error while making health channel state change callback: " + e);
+ IBluetoothHealthCallback callback = mCallbacks.get(config);
+ if (callback != null) {
+ try {
+ callback.onHealthChannelStateChange(config, device, prevState, state, fd);
+ } catch (RemoteException e) {}
}
}
@@ -454,10 +453,11 @@
BluetoothHealthAppConfiguration config, int status) {
debugLog("Health Device Application: " + config + " State Change: status:"
+ status);
- try {
- config.getCallback().onHealthAppConfigurationStatusChange(config, status);
- } catch (RemoteException e) {
- errorLog("Error while making health app registration state change callback: " + e);
+ IBluetoothHealthCallback callback = mCallbacks.get(config);
+ if (callback != null) {
+ try {
+ callback.onHealthAppConfigurationStatusChange(config, status);
+ } catch (RemoteException e) {}
}
}
@@ -526,19 +526,19 @@
List<HealthChannel> chan;
switch (currDeviceState) {
case BluetoothHealth.STATE_DISCONNECTED:
- updateAndsendIntent(device, currDeviceState, newDeviceState);
+ updateAndSendIntent(device, currDeviceState, newDeviceState);
break;
case BluetoothHealth.STATE_CONNECTING:
// Channel got connected.
if (newDeviceState == BluetoothHealth.STATE_CONNECTED) {
- updateAndsendIntent(device, currDeviceState, newDeviceState);
+ updateAndSendIntent(device, currDeviceState, newDeviceState);
} else {
// Channel got disconnected
chan = findChannelByStates(device, new int [] {
BluetoothHealth.STATE_CHANNEL_CONNECTING,
BluetoothHealth.STATE_CHANNEL_DISCONNECTING});
if (chan.isEmpty()) {
- updateAndsendIntent(device, currDeviceState, newDeviceState);
+ updateAndSendIntent(device, currDeviceState, newDeviceState);
}
}
break;
@@ -548,22 +548,23 @@
BluetoothHealth.STATE_CHANNEL_CONNECTING,
BluetoothHealth.STATE_CHANNEL_CONNECTED});
if (chan.isEmpty()) {
- updateAndsendIntent(device, currDeviceState, newDeviceState);
+ updateAndSendIntent(device, currDeviceState, newDeviceState);
}
+ break;
case BluetoothHealth.STATE_DISCONNECTING:
// Channel got disconnected.
chan = findChannelByStates(device, new int [] {
BluetoothHealth.STATE_CHANNEL_CONNECTING,
BluetoothHealth.STATE_CHANNEL_DISCONNECTING});
if (chan.isEmpty()) {
- updateAndsendIntent(device, currDeviceState, newDeviceState);
+ updateAndSendIntent(device, currDeviceState, newDeviceState);
}
break;
}
}
}
- private void updateAndsendIntent(BluetoothDevice device, int prevDeviceState,
+ private void updateAndSendIntent(BluetoothDevice device, int prevDeviceState,
int newDeviceState) {
mHealthDevices.put(device, newDeviceState);
mBluetoothService.sendConnectionStateChange(device, prevDeviceState, newDeviceState);
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
old mode 100644
new mode 100755
index 9839f76..b23e3ce
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -24,8 +24,6 @@
package android.server;
-import com.android.internal.app.IBatteryStats;
-
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -40,6 +38,7 @@
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothHealthCallback;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -58,6 +57,8 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.app.IBatteryStats;
+
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -2111,11 +2112,12 @@
/**** Handlers for Health Device Profile ****/
// TODO: All these need to be converted to a state machine.
- public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config) {
+ public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config,
+ IBluetoothHealthCallback callback) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
"Need BLUETOOTH permission");
synchronized (mBluetoothHealthProfileHandler) {
- return mBluetoothHealthProfileHandler.registerAppConfiguration(config);
+ return mBluetoothHealthProfileHandler.registerAppConfiguration(config, callback);
}
}
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index b7aea20..1dcbc26 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -3849,10 +3849,6 @@
}
private static int checkCallingPermission(String permission) {
- if (!Process.supportsProcesses()) {
- return PackageManager.PERMISSION_GRANTED;
- }
-
try {
return ActivityManagerNative.getDefault().checkPermission(
permission, Binder.getCallingPid(), Binder.getCallingUid());
diff --git a/core/java/android/webkit/L10nUtils.java b/core/java/android/webkit/L10nUtils.java
index f9d0067d..a1c6a53 100644
--- a/core/java/android/webkit/L10nUtils.java
+++ b/core/java/android/webkit/L10nUtils.java
@@ -75,7 +75,18 @@
com.android.internal.R.string.autofill_area_code_notext_re, // IDS_AUTOFILL_AREA_CODE_NOTEXT_RE
com.android.internal.R.string.autofill_phone_prefix_separator_re, // IDS_AUTOFILL_PHONE_PREFIX_SEPARATOR_RE
com.android.internal.R.string.autofill_phone_suffix_separator_re, // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE
- com.android.internal.R.string.credit_card_number_preview_format // IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT
+ com.android.internal.R.string.autofill_province, // IDS_AUTOFILL_DIALOG_PROVINCE
+ com.android.internal.R.string.autofill_postal_code, // IDS_AUTOFILL_DIALOG_POSTAL_CODE
+ com.android.internal.R.string.autofill_state, // IDS_AUTOFILL_DIALOG_STATE
+ com.android.internal.R.string.autofill_zip_code, // IDS_AUTOFILL_DIALOG_ZIP_CODE
+ com.android.internal.R.string.autofill_county, // IDS_AUTOFILL_DIALOG_COUNTY
+ com.android.internal.R.string.autofill_island, // IDS_AUTOFILL_DIALOG_ISLAND
+ com.android.internal.R.string.autofill_district, // IDS_AUTOFILL_DIALOG_DISTRICT
+ com.android.internal.R.string.autofill_department, // IDS_AUTOFILL_DIALOG_DEPARTMENT
+ com.android.internal.R.string.autofill_prefecture, // IDS_AUTOFILL_DIALOG_PREFECTURE
+ com.android.internal.R.string.autofill_parish, // IDS_AUTOFILL_DIALOG_PARISH
+ com.android.internal.R.string.autofill_area, // IDS_AUTOFILL_DIALOG_AREA
+ com.android.internal.R.string.autofill_emirate // IDS_AUTOFILL_DIALOG_EMIRATE
};
private static Context mApplicationContext;
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 7d3f313..49ea944 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -344,6 +344,8 @@
public final void setInitialScaleInPercent(int scaleInPercent) {
mInitialScale = scaleInPercent * 0.01f;
+ mActualScale = mInitialScale > 0 ? mInitialScale : mDefaultScale;
+ mInvActualScale = 1 / mActualScale;
}
public final float computeScaleWithLimits(float scale) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e350ec4..766b520 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6212,6 +6212,15 @@
int scrollx, scrolly;
+ // Convert to left, center, or right alignment.
+ if (a == Layout.Alignment.ALIGN_NORMAL) {
+ a = dir == Layout.DIR_LEFT_TO_RIGHT ? Layout.Alignment.ALIGN_LEFT :
+ Layout.Alignment.ALIGN_RIGHT;
+ } else if (a == Layout.Alignment.ALIGN_OPPOSITE){
+ a = dir == Layout.DIR_LEFT_TO_RIGHT ? Layout.Alignment.ALIGN_RIGHT :
+ Layout.Alignment.ALIGN_LEFT;
+ }
+
if (a == Layout.Alignment.ALIGN_CENTER) {
/*
* Keep centered if possible, or, if it is too wide to fit,
@@ -6230,28 +6239,11 @@
scrollx = left;
}
}
- } else if (a == Layout.Alignment.ALIGN_NORMAL) {
- /*
- * Keep leading edge in view.
- */
-
- if (dir < 0) {
- int right = (int) FloatMath.ceil(mLayout.getLineRight(line));
- scrollx = right - hspace;
- } else {
- scrollx = (int) FloatMath.floor(mLayout.getLineLeft(line));
- }
- } else /* a == Layout.Alignment.ALIGN_OPPOSITE */ {
- /*
- * Keep trailing edge in view.
- */
-
- if (dir < 0) {
- scrollx = (int) FloatMath.floor(mLayout.getLineLeft(line));
- } else {
- int right = (int) FloatMath.ceil(mLayout.getLineRight(line));
- scrollx = right - hspace;
- }
+ } else if (a == Layout.Alignment.ALIGN_LEFT) {
+ scrollx = (int) FloatMath.floor(mLayout.getLineLeft(line));
+ } else { // a == Layout.Alignment.ALIGN_RIGHT
+ int right = (int) FloatMath.ceil(mLayout.getLineRight(line));
+ scrollx = right - hspace;
}
if (ht < vspace) {
@@ -6293,20 +6285,24 @@
int grav;
switch (mLayout.getParagraphAlignment(line)) {
- case ALIGN_NORMAL:
+ case ALIGN_LEFT:
grav = 1;
break;
-
- case ALIGN_OPPOSITE:
+ case ALIGN_RIGHT:
grav = -1;
break;
-
+ case ALIGN_NORMAL:
+ grav = mLayout.getParagraphDirection(line);
+ break;
+ case ALIGN_OPPOSITE:
+ grav = -mLayout.getParagraphDirection(line);
+ break;
+ case ALIGN_CENTER:
default:
grav = 0;
+ break;
}
- grav *= mLayout.getParagraphDirection(line);
-
int hspace = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
int vspace = mBottom - mTop - getExtendedPaddingTop() - getExtendedPaddingBottom();
diff --git a/core/java/com/android/internal/os/PkgUsageStats.java b/core/java/com/android/internal/os/PkgUsageStats.java
index 1ac191b..8c2c405 100755
--- a/core/java/com/android/internal/os/PkgUsageStats.java
+++ b/core/java/com/android/internal/os/PkgUsageStats.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* implementation of PkgUsageStats associated with an
* application package.
@@ -28,6 +31,7 @@
public String packageName;
public int launchCount;
public long usageTime;
+ public Map<String, Long> componentResumeTimes;
public static final Parcelable.Creator<PkgUsageStats> CREATOR
= new Parcelable.Creator<PkgUsageStats>() {
@@ -46,31 +50,45 @@
+ " " + packageName + "}";
}
- public PkgUsageStats(String pkgName, int count, long time) {
+ public PkgUsageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) {
packageName = pkgName;
launchCount = count;
usageTime = time;
+ componentResumeTimes = new HashMap<String, Long>(lastResumeTimes);
}
public PkgUsageStats(Parcel source) {
packageName = source.readString();
launchCount = source.readInt();
usageTime = source.readLong();
+ final int N = source.readInt();
+ componentResumeTimes = new HashMap<String, Long>(N);
+ for (int i = 0; i < N; i++) {
+ String component = source.readString();
+ long lastResumeTime = source.readLong();
+ componentResumeTimes.put(component, lastResumeTime);
+ }
}
public PkgUsageStats(PkgUsageStats pStats) {
packageName = pStats.packageName;
launchCount = pStats.launchCount;
usageTime = pStats.usageTime;
+ componentResumeTimes = new HashMap<String, Long>(pStats.componentResumeTimes);
}
public int describeContents() {
return 0;
}
- public void writeToParcel(Parcel dest, int parcelableFlags){
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeString(packageName);
dest.writeInt(launchCount);
dest.writeLong(usageTime);
+ dest.writeInt(componentResumeTimes.size());
+ for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) {
+ dest.writeString(ent.getKey());
+ dest.writeLong(ent.getValue());
+ }
}
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index fcac2ac..9af7e96 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -518,10 +518,6 @@
"--runtime-init and -classpath are incompatible");
}
- if (!targetSdkVersionSpecified) {
- targetSdkVersion = Build.VERSION.SDK_INT;
- }
-
remainingArgs = new String[args.length - curArg];
System.arraycopy(args, curArg, remainingArgs, 0,
@@ -904,6 +900,7 @@
}
}
+ boolean usingWrapper = false;
if (pipeFd != null && pid > 0) {
DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));
int innerPid = -1;
@@ -928,6 +925,7 @@
if (parentPid > 0) {
Log.i(TAG, "Wrapped process has pid " + innerPid);
pid = innerPid;
+ usingWrapper = true;
} else {
Log.w(TAG, "Wrapped process reported a pid that is not a child of "
+ "the process that we forked: childPid=" + pid
@@ -938,6 +936,7 @@
try {
mSocketOutStream.writeInt(pid);
+ mSocketOutStream.writeBoolean(usingWrapper);
} catch (IOException ex) {
Log.e(TAG, "Error reading from command socket", ex);
return true;
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index b86eb13..9c06d69 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -20,7 +20,8 @@
import android.content.Context;
import android.content.res.Resources;
-import android.util.Log;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.util.SparseBooleanArray;
import android.view.MenuItem;
import android.view.SoundEffectConstants;
@@ -60,6 +61,9 @@
private OpenOverflowRunnable mPostedOpenRunnable;
+ final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
+ int mOpenSubMenuId;
+
public ActionMenuPresenter() {
super(com.android.internal.R.layout.action_menu_layout,
com.android.internal.R.layout.action_menu_item_layout);
@@ -196,8 +200,12 @@
topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu();
}
View anchor = findViewForItem(topSubMenu.getItem());
- if (anchor == null) return false;
+ if (anchor == null) {
+ if (mOverflowButton == null) return false;
+ anchor = mOverflowButton;
+ }
+ mOpenSubMenuId = subMenu.getItem().getItemId();
mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu);
mActionButtonPopup.setAnchorView(anchor);
mActionButtonPopup.show();
@@ -426,6 +434,57 @@
super.onCloseMenu(menu, allMenusAreClosing);
}
+ @Override
+ public Parcelable onSaveInstanceState() {
+ SavedState state = new SavedState();
+ state.openSubMenuId = mOpenSubMenuId;
+ return state;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ SavedState saved = (SavedState) state;
+ if (saved.openSubMenuId > 0) {
+ MenuItem item = mMenu.findItem(saved.openSubMenuId);
+ if (item != null) {
+ SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+ onSubMenuSelected(subMenu);
+ }
+ }
+ }
+
+ private static class SavedState implements Parcelable {
+ public int openSubMenuId;
+
+ SavedState() {
+ }
+
+ SavedState(Parcel in) {
+ openSubMenuId = in.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(openSubMenuId);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR
+ = new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
private class OverflowMenuButton extends ImageButton implements ActionMenuChildView {
public OverflowMenuButton(Context context) {
super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle);
@@ -460,6 +519,7 @@
public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
boolean overflowOnly) {
super(context, menu, anchorView, overflowOnly);
+ setCallback(mPopupPresenterCallback);
}
@Override
@@ -482,6 +542,8 @@
// Give a reasonable anchor to nested submenus.
setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton);
}
+
+ setCallback(mPopupPresenterCallback);
}
@Override
@@ -489,6 +551,20 @@
super.onDismiss();
mSubMenu.close();
mActionButtonPopup = null;
+ mOpenSubMenuId = 0;
+ }
+ }
+
+ private class PopupPresenterCallback implements MenuPresenter.Callback {
+
+ @Override
+ public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
+ return false;
+ }
+
+ @Override
+ public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
}
}
diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
index ddbb08c..ed9d34a 100644
--- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
@@ -39,6 +39,8 @@
protected MenuView mMenuView;
+ private int mId;
+
/**
* Construct a new BaseMenuPresenter.
*
@@ -200,4 +202,12 @@
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
return false;
}
+
+ public int getId() {
+ return mId;
+ }
+
+ public void setId(int id) {
+ mId = id;
+ }
}
diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
index f717904..56128d4 100644
--- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
@@ -23,6 +23,7 @@
import android.util.SparseArray;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -35,7 +36,12 @@
private IconMenuItemView mMoreView;
private int mMaxItems = -1;
+ int mOpenSubMenuId;
+ SubMenuPresenterCallback mSubMenuPresenterCallback = new SubMenuPresenterCallback();
+ MenuDialogHelper mOpenSubMenu;
+
private static final String VIEWS_TAG = "android:menu:icon";
+ private static final String OPEN_SUBMENU_KEY = "android:menu:icon:submenu";
public IconMenuPresenter() {
super(com.android.internal.R.layout.icon_menu_layout,
@@ -86,7 +92,11 @@
if (!subMenu.hasVisibleItems()) return false;
// The window manager will give us a token.
- new MenuDialogHelper(subMenu).show(null);
+ MenuDialogHelper helper = new MenuDialogHelper(subMenu);
+ helper.setPresenterCallback(mSubMenuPresenterCallback);
+ helper.show(null);
+ mOpenSubMenu = helper;
+ mOpenSubMenuId = subMenu.getItem().getItemId();
super.onSubMenuSelected(subMenu);
return true;
}
@@ -137,5 +147,47 @@
if (viewStates != null) {
((View) mMenuView).restoreHierarchyState(viewStates);
}
+ int subMenuId = inState.getInt(OPEN_SUBMENU_KEY, 0);
+ if (subMenuId > 0 && mMenu != null) {
+ MenuItem item = mMenu.findItem(subMenuId);
+ if (item != null) {
+ onSubMenuSelected((SubMenuBuilder) item.getSubMenu());
+ }
+ }
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ if (mMenuView == null) {
+ return null;
+ }
+
+ Bundle state = new Bundle();
+ saveHierarchyState(state);
+ if (mOpenSubMenuId > 0) {
+ state.putInt(OPEN_SUBMENU_KEY, mOpenSubMenuId);
+ }
+ return state;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ restoreHierarchyState((Bundle) state);
+ }
+
+ class SubMenuPresenterCallback implements MenuPresenter.Callback {
+ @Override
+ public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+ mOpenSubMenuId = 0;
+ mOpenSubMenu.dismiss();
+ mOpenSubMenu = null;
+ }
+
+ @Override
+ public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
+ return false;
+ }
+
}
}
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index 27e4191..146c7ac 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -47,6 +47,8 @@
private Callback mCallback;
private MenuAdapter mAdapter;
+ private int mId;
+
public static final String VIEWS_TAG = "android:menu:list";
/**
@@ -182,6 +184,31 @@
}
}
+ public void setId(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ if (mMenuView == null) {
+ return null;
+ }
+
+ Bundle state = new Bundle();
+ saveHierarchyState(state);
+ return state;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ restoreHierarchyState((Bundle) state);
+ }
+
private class MenuAdapter extends BaseAdapter {
public int getCount() {
ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index fdfa954..a4edbc5 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -25,8 +25,8 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Parcelable;
-import android.util.Log;
import android.util.SparseArray;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyCharacterMap;
@@ -38,7 +38,6 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -49,6 +48,8 @@
public class MenuBuilder implements Menu {
private static final String LOGTAG = "MenuBuilder";
+ private static final String PRESENTER_KEY = "android:menu:presenters";
+
private static final int[] sCategoryToOrder = new int[] {
1, /* No category */
4, /* CONTAINER */
@@ -254,6 +255,58 @@
return result;
}
+ private void dispatchSaveInstanceState(Bundle outState) {
+ if (mPresenters.isEmpty()) return;
+
+ SparseArray<Parcelable> presenterStates = new SparseArray<Parcelable>();
+
+ for (WeakReference<MenuPresenter> ref : mPresenters) {
+ final MenuPresenter presenter = ref.get();
+ if (presenter == null) {
+ mPresenters.remove(ref);
+ } else {
+ final int id = presenter.getId();
+ if (id > 0) {
+ final Parcelable state = presenter.onSaveInstanceState();
+ if (state != null) {
+ presenterStates.put(id, state);
+ }
+ }
+ }
+ }
+
+ outState.putSparseParcelableArray(PRESENTER_KEY, presenterStates);
+ }
+
+ private void dispatchRestoreInstanceState(Bundle state) {
+ SparseArray<Parcelable> presenterStates = state.getSparseParcelableArray(PRESENTER_KEY);
+
+ if (presenterStates == null || mPresenters.isEmpty()) return;
+
+ for (WeakReference<MenuPresenter> ref : mPresenters) {
+ final MenuPresenter presenter = ref.get();
+ if (presenter == null) {
+ mPresenters.remove(ref);
+ } else {
+ final int id = presenter.getId();
+ if (id > 0) {
+ Parcelable parcel = presenterStates.get(id);
+ if (parcel != null) {
+ presenter.onRestoreInstanceState(parcel);
+ }
+ }
+ }
+ }
+ }
+
+ public void savePresenterStates(Bundle outState) {
+ dispatchSaveInstanceState(outState);
+ }
+
+ public void restorePresenterStates(Bundle state) {
+ dispatchRestoreInstanceState(state);
+ }
+
public void setCallback(Callback cb) {
mCallback = cb;
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index cffbb4e..4ecc828 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.Resources;
+import android.os.Parcelable;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -296,4 +297,18 @@
return convertView;
}
}
+
+ @Override
+ public int getId() {
+ return 0;
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ return null;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ }
}
diff --git a/core/java/com/android/internal/view/menu/MenuPresenter.java b/core/java/com/android/internal/view/menu/MenuPresenter.java
index bd66448..d913a39 100644
--- a/core/java/com/android/internal/view/menu/MenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/MenuPresenter.java
@@ -17,6 +17,7 @@
package com.android.internal.view.menu;
import android.content.Context;
+import android.os.Parcelable;
import android.view.Menu;
import android.view.ViewGroup;
@@ -125,4 +126,24 @@
* @return true if this presenter collapsed the action view, false otherwise.
*/
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item);
+
+ /**
+ * Returns an ID for determining how to save/restore instance state.
+ * @return a valid ID value.
+ */
+ public int getId();
+
+ /**
+ * Returns a Parcelable describing the current state of the presenter.
+ * It will be passed to the {@link #onRestoreInstanceState(Parcelable)}
+ * method of the presenter sharing the same ID later.
+ * @return The saved instance state
+ */
+ public Parcelable onSaveInstanceState();
+
+ /**
+ * Supplies the previously saved instance state to be restored.
+ * @param state The previously saved instance state
+ */
+ public void onRestoreInstanceState(Parcelable state);
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 09bc1fc..595753a 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -337,6 +337,7 @@
if (mActionMenuPresenter == null) {
mActionMenuPresenter = new ActionMenuPresenter();
mActionMenuPresenter.setCallback(cb);
+ mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter);
mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
}
@@ -1301,5 +1302,19 @@
item.setActionViewExpanded(false);
return true;
}
+
+ @Override
+ public int getId() {
+ return 0;
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ return null;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ }
}
}
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index 1166ae4..86e7cc0 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -1396,7 +1396,6 @@
LOG_AND_FREE_DBUS_ERROR(&err);
}
} else {
- LOGE("--_Call made getting the patch...");
if (!dbus_message_get_args(reply, &err,
DBUS_TYPE_OBJECT_PATH, &c_path,
DBUS_TYPE_INVALID)) {
@@ -1405,7 +1404,6 @@
}
} else {
path = env->NewStringUTF(c_path);
- LOGE("----Path is %s", c_path);
}
dbus_message_unref(reply);
}
@@ -1459,7 +1457,6 @@
const char *c_device_path = env->GetStringUTFChars(devicePath, NULL);
const char *c_app_path = env->GetStringUTFChars(appPath, NULL);
const char *c_config = env->GetStringUTFChars(config, NULL);
- LOGE("Params...%s, %s, %s \n", c_device_path, c_app_path, c_config);
DBusMessage *reply = dbus_func_args(env, nat->conn,
c_device_path,
@@ -1531,7 +1528,6 @@
DBusError err;
dbus_error_init(&err);
- LOGE("---Args %s", c_device_path);
DBusMessage *reply = dbus_func_args(env, nat->conn,
c_device_path,
DBUS_HEALTH_DEVICE_IFACE, "GetProperties",
@@ -1566,8 +1562,6 @@
DBusError err;
dbus_error_init(&err);
- LOGE("---Args %s", c_channel_path);
-
DBusMessage *reply = dbus_func_args(env, nat->conn,
c_channel_path,
DBUS_HEALTH_CHANNEL_IFACE, "GetProperties",
@@ -1596,7 +1590,6 @@
if (!strcmp(c_name, "Application")) {
path = (jstring) env->GetObjectArrayElement(str_array, i+1);
- LOGE("----Path is %s", env->GetStringUTFChars(path, NULL));
env->ReleaseStringUTFChars(name, c_name);
return path;
}
@@ -1655,13 +1648,11 @@
fd = dbus_returns_unixfd(env, reply);
if (fd == -1) return NULL;
- LOGE("---got fd %d\n", fd);
// Create FileDescriptor object
jobject fileDesc = jniCreateFileDescriptor(env, fd);
if (fileDesc == NULL) {
// FileDescriptor constructor has thrown an exception
releaseChannelFdNative(env, object, channelPath);
- LOGE("---File Desc is null");
return NULL;
}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 0960b25..d1ba2d1 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -318,17 +318,15 @@
jint pid, jint adj)
{
#ifdef HAVE_OOM_ADJ
- if (ProcessState::self()->supportsProcesses()) {
- char text[64];
- sprintf(text, "/proc/%d/oom_adj", pid);
- int fd = open(text, O_WRONLY);
- if (fd >= 0) {
- sprintf(text, "%d", adj);
- write(fd, text, strlen(text));
- close(fd);
- }
- return true;
+ char text[64];
+ sprintf(text, "/proc/%d/oom_adj", pid);
+ int fd = open(text, O_WRONLY);
+ if (fd >= 0) {
+ sprintf(text, "%d", adj);
+ write(fd, text, strlen(text));
+ close(fd);
}
+ return true;
#endif
return false;
}
@@ -370,11 +368,6 @@
#endif
}
-jboolean android_os_Process_supportsProcesses(JNIEnv* env, jobject clazz)
-{
- return ProcessState::self()->supportsProcesses();
-}
-
static int pid_compare(const void* v1, const void* v2)
{
//LOGI("Compare %d vs %d\n", *((const jint*)v1), *((const jint*)v2));
@@ -878,7 +871,6 @@
{"setGid", "(I)I", (void*)android_os_Process_setGid},
{"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
{"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
- {"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
{"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
{"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
{"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
index 5225a81..acbbb38 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
index 2e7e973..6009528 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
index 4591627..30727d7 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
index 9cf1826..7cea5e1 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
index a47ef40..ba0d612 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
index 9b50c73..e8646b9 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
index a0d36de..14cb4c9 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
index 805b9567..80fd218 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
index b0fba52..1014d8a 100644
--- a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
index 3ef8935..18cd171 100644
--- a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png
index 9769bbb7..ad2cb5a 100644
--- a/core/res/res/drawable-hdpi/toast_frame.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame_holo.9.png b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
index 9769bbb7..ad2cb5a 100644
--- a/core/res/res/drawable-hdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
index a0bd4e3..4836da1 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
index 12abcd2..c299931 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
index adb8104..86edad7 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
index d7c6bbf..53ee68b 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
index 42cfc52..606adaf 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
index 9a08e15..14d2e5e 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
index 5d86b2a..2646332 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
index ad22f5b..48ec0a4 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
index 923f92d..dd5dd39 100644
--- a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
index afada39..12d65be 100644
--- a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png
index 06cfc70..b9105de 100755
--- a/core/res/res/drawable-mdpi/toast_frame.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame_holo.9.png b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
index 06cfc70..b9105de 100755
--- a/core/res/res/drawable-mdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
index b33e117..077e4d3 100644
--- a/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
index d84d427..357c17f 100644
--- a/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
index 9c0ff47..5b510721 100644
--- a/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
index 331a4f2..2705a39 100644
--- a/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
index cdc887d..101876f 100644
--- a/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
index bdb6824..0df1503 100644
--- a/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
index 600efb3..344a4e2 100644
--- a/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
index aa8401d..249848f 100644
--- a/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png
new file mode 100644
index 0000000..92acc47
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_light.9.png
new file mode 100644
index 0000000..4e54b4b6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame.9.png b/core/res/res/drawable-xhdpi/toast_frame.9.png
index f7debee..9f39a77 100644
--- a/core/res/res/drawable-xhdpi/toast_frame.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
index f7debee..9f39a77 100644
--- a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index d05685c..547a192 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -74,4 +74,9 @@
<item type="id" name="rowTypeId" />
<item type="id" name="up" />
<item type="id" name="action_menu_divider" />
+ <item type="id" name="icon_menu_presenter" />
+ <item type="id" name="list_menu_presenter" />
+ <item type="id" name="action_menu_presenter" />
+ <item type="id" name="overflow_menu_presenter" />
+ <item type="id" name="popup_submenu_presenter" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 97a8c0b..70c204e 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2038,13 +2038,13 @@
<string name="autofill_phone_re">phone<!-- de-DE -->|telefonnummer<!-- es -->|telefono|teléfono<!-- fr-FR -->|telfixe<!-- ja-JP -->|電話<!-- pt-BR, pt-PT -->|telefone|telemovel<!-- ru -->|телефон<!-- zh-CN -->|电话</string>
<!-- Do not translate. Regex used by AutoFill. -->
- <string name="autofill_area_code_re">area code</string>
+ <string name="autofill_area_code_re">area.*code|acode|area</string>
<!-- Do not translate. Regex used by AutoFill. -->
- <string name="autofill_phone_prefix_re">^-$|\\)$|prefix<!-- fr-FR -->|preselection<!-- pt-BR, pt-PT -->|ddd</string>
+ <string name="autofill_phone_prefix_re">prefix<!-- fr-FR -->|preselection<!-- pt-BR, pt-PT -->|ddd</string>
<!-- Do not translate. Regex used by AutoFill. -->
- <string name="autofill_phone_suffix_re">^-$|suffix</string>
+ <string name="autofill_phone_suffix_re">suffix</string>
<!-- Do not translate. Regex used by AutoFill. -->
<string name="autofill_phone_extension_re">ext<!-- pt-BR, pt-PT -->|ramal</string>
@@ -2077,17 +2077,49 @@
<string name="autofill_country_code_re">country.*code|ccode|_cc</string>
<!-- Do not translate. Regex used by AutoFill. -->
- <string name="autofill_area_code_notext_re">^\($</string>
+ <string name="autofill_area_code_notext_re">^\\($</string>
<!-- Do not translate. Regex used by AutoFill. -->
- <string name="autofill_phone_prefix_separator_re">^-$|^\)$</string>
+ <string name="autofill_phone_prefix_separator_re">^-$|^\\)$</string>
<!-- Do not translate. Regex used by AutoFill. -->
<string name="autofill_phone_suffix_separator_re">^-$</string>
- <!-- Do not translate. Regex used by AutoFill. -->
- <!-- Ex: ************1234 -->
- <string name="credit_card_number_preview_format">$1</string>
+ <!-- Label in a web form for "Province" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_province">Province</string>
+
+ <!-- Label in a web form for "Postal code" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_postal_code">Postal code</string>
+
+ <!-- Label in a web form for "State" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_state">State</string>
+
+ <!-- Label in a web form for "ZIP code" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_zip_code">ZIP code</string>
+
+ <!-- Label in a web form for "County" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_county">County</string>
+
+ <!-- Label in a web form for "Island" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_island">Island</string>
+
+ <!-- Label in a web form for "District" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_district">District</string>
+
+ <!-- Label in a web form for "Department" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_department">Department</string>
+
+ <!-- Label in a web form for "Prefecture" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_prefecture">Prefecture</string>
+
+ <!-- Label in a web form for "Parish" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_parish">Parish</string>
+
+ <!-- Label in a web form for "Area" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_area">Area</string>
+
+ <!-- Label in a web form for "Emirate" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_emirate">Emirate</string>
<!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 00f47fa..b2ebb08 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -12,7 +12,7 @@
$(call all-java-files-under, EnabledTestApp/src)
LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver guava
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 40fa552..146466f 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1242,6 +1242,13 @@
</intent-filter>
</activity>
+ <activity android:name="android.animation.BasicAnimatorActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/core/tests/coretests/res/layout/animator_basic.xml b/core/tests/coretests/res/layout/animator_basic.xml
new file mode 100644
index 0000000..7b8ef11
--- /dev/null
+++ b/core/tests/coretests/res/layout/animator_basic.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/animatingButton"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
new file mode 100644
index 0000000..65f2b8e
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
@@ -0,0 +1,39 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package android.animation;
+
+import android.widget.Button;
+import com.android.frameworks.coretests.R;
+
+/**
+ * Listener tests for AnimatorSet.
+ */
+public class AnimatorSetEventsTest extends EventsTest {
+
+ @Override
+ public void setUp() throws Exception {
+ final BasicAnimatorActivity activity = getActivity();
+ Button button = (Button) activity.findViewById(R.id.animatingButton);
+
+ ObjectAnimator xAnim = ObjectAnimator.ofFloat(button, "translationX", 0, 100);
+ ObjectAnimator yAnim = ObjectAnimator.ofFloat(button, "translationX", 0, 100);
+ mAnimator = new AnimatorSet();
+ ((AnimatorSet)mAnimator).playSequentially(xAnim, yAnim);
+
+ super.setUp();
+ }
+
+}
diff --git a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
new file mode 100644
index 0000000..93808d9
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.animation;
+
+import com.android.frameworks.coretests.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class BasicAnimatorActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.animator_basic);
+ }
+}
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
new file mode 100644
index 0000000..f970ffc
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.animation;
+
+import android.os.Handler;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests for the various lifecycle events of Animators. This abstract class is subclassed by
+ * concrete implementations that provide the actual Animator objects being tested. All of the
+ * testing mechanisms are in this class; the subclasses are only responsible for providing
+ * the mAnimator object.
+ *
+ * This test is more complicated than a typical synchronous test because much of the functionality
+ * must happen on the UI thread. Some tests do this by using the UiThreadTest annotation to
+ * automatically run the whole test on that thread. Other tests must run on the UI thread and also
+ * wait for some later event to occur before ending. These tests use a combination of an
+ * AbstractFuture mechanism and a delayed action to release that Future later.
+ */
+public abstract class EventsTest
+ extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+
+ private static final int ANIM_DURATION = 400;
+ private static final int ANIM_DELAY = 100;
+ private static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
+ private static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
+
+ private boolean mRunning; // tracks whether we've started the animator
+ private boolean mCanceled; // trackes whether we've canceled the animator
+ private Animator.AnimatorListener mFutureListener; // mechanism for delaying the end of the test
+ private FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
+ private Animator.AnimatorListener mListener; // Listener that handles/tests the events
+
+ protected Animator mAnimator; // The animator used in the tests. Must be set in subclass
+ // setup() method prior to calling the superclass setup()
+
+ /**
+ * Cancels the given animator. Used to delay cancelation until some later time (after the
+ * animator has started playing).
+ */
+ static class Canceler implements Runnable {
+ Animator mAnim;
+ public Canceler(Animator anim) {
+ mAnim = anim;
+ }
+ @Override
+ public void run() {
+ mAnim.cancel();
+ }
+ };
+
+ /**
+ * Releases the given Future object when the listener's end() event is called. Specifically,
+ * it releases it after some further delay, to give the test time to do other things right
+ * after an animation ends.
+ */
+ static class FutureReleaseListener extends AnimatorListenerAdapter {
+ FutureWaiter mFuture;
+
+ public FutureReleaseListener(FutureWaiter future) {
+ mFuture = future;
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ Handler handler = new Handler();
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mFuture.release();
+ }
+ }, ANIM_MID_DURATION);
+ }
+ };
+
+ public EventsTest() {
+ super(BasicAnimatorActivity.class);
+ }
+
+
+ /**
+ * Sets up the fields used by each test. Subclasses must override this method to create
+ * the protected mAnimator object used in all tests. Overrides must create that animator
+ * and then call super.setup(), where further properties are set on that animator.
+ * @throws Exception
+ */
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // mListener is the main testing mechanism of this file. The asserts of each test
+ // are embedded in the listener callbacks that it implements.
+ mListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ // This should only be called on an animation that has been started and not
+ // yet canceled or ended
+ assertFalse(mCanceled);
+ assertTrue(mRunning);
+ mCanceled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // This should only be called on an animation that has been started and not
+ // yet ended
+ assertTrue(mRunning);
+ mRunning = false;
+ super.onAnimationEnd(animation);
+ }
+ };
+
+ mAnimator.addListener(mListener);
+ mAnimator.setDuration(ANIM_DURATION);
+
+ mFuture = new FutureWaiter();
+
+ mRunning = false;
+ mCanceled = false;
+ }
+
+ /**
+ * Verify that calling cancel on an unstarted animator does nothing.
+ */
+ @UiThreadTest
+ @SmallTest
+ public void testCancel() throws Exception {
+ mAnimator.cancel();
+ }
+
+ /**
+ * Verify that calling cancel on a started animator does the right thing.
+ */
+ @UiThreadTest
+ @SmallTest
+ public void testStartCancel() throws Exception {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.cancel();
+ }
+
+ /**
+ * Same as testStartCancel, but with a startDelayed animator
+ */
+ @UiThreadTest
+ @SmallTest
+ public void testStartDelayedCancel() throws Exception {
+ mAnimator.setStartDelay(ANIM_DELAY);
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.cancel();
+ }
+
+ /**
+ * Verify that canceling an animator that is playing does the right thing.
+ */
+ @MediumTest
+ public void testPlayingCancel() throws Exception {
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Handler handler = new Handler();
+ mAnimator.addListener(mFutureListener);
+ mRunning = true;
+ mAnimator.start();
+ handler.postDelayed(new Canceler(mAnimator), ANIM_MID_DURATION);
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get();
+ }
+
+ /**
+ * Same as testPlayingCancel, but with a startDelayed animator
+ */
+ @MediumTest
+ public void testPlayingDelayedCancel() throws Exception {
+ mAnimator.setStartDelay(ANIM_DELAY);
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Handler handler = new Handler();
+ mAnimator.addListener(mFutureListener);
+ mRunning = true;
+ mAnimator.start();
+ handler.postDelayed(new Canceler(mAnimator), ANIM_MID_DURATION);
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get();
+ }
+
+ /**
+ * Verifies that canceling a started animation after it has already been canceled
+ * does nothing.
+ */
+ @MediumTest
+ public void testStartDoubleCancel() throws Exception {
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.cancel();
+ mAnimator.cancel();
+ mFuture.release();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get();
+ }
+
+ /**
+ * Same as testStartDoubleCancel, but with a startDelayed animator
+ */
+ @MediumTest
+ public void testStartDelayedDoubleCancel() throws Exception {
+ mAnimator.setStartDelay(ANIM_DELAY);
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.cancel();
+ mAnimator.cancel();
+ mFuture.release();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get();
+ }
+
+
+}
diff --git a/core/tests/coretests/src/android/animation/FutureWaiter.java b/core/tests/coretests/src/android/animation/FutureWaiter.java
new file mode 100644
index 0000000..320a1c2
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/FutureWaiter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.animation;
+
+import com.google.common.util.concurrent.AbstractFuture;
+
+/**
+ * Simple extension of {@link com.google.common.util.concurrent.AbstractFuture} which exposes a new
+ * release() method which calls the protected
+ * {@link com.google.common.util.concurrent.AbstractFuture#set(Object)} method internally. It
+ * also exposes the protected {@link AbstractFuture#setException(Throwable)} method.
+ */
+public class FutureWaiter extends AbstractFuture<Void> {
+
+ /**
+ * Release the Future currently waiting on
+ * {@link com.google.common.util.concurrent.AbstractFuture#get()}.
+ */
+ public void release() {
+ super.set(null);
+ }
+
+ @Override
+ public boolean setException(Throwable throwable) {
+ return super.setException(throwable);
+ }
+}
diff --git a/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
new file mode 100644
index 0000000..606a939
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.animation;
+
+import android.widget.Button;
+import com.android.frameworks.coretests.R;
+
+/**
+ * Listener tests for ObjectAnimator.
+ */
+public class ObjectAnimatorEventsTest extends EventsTest {
+
+ @Override
+ public void setUp() throws Exception {
+ final BasicAnimatorActivity activity = getActivity();
+ Button button = (Button) activity.findViewById(R.id.animatingButton);
+
+ mAnimator = ObjectAnimator.ofFloat(button, "translationX", 0, 100);
+ super.setUp();
+ }
+
+}
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
new file mode 100644
index 0000000..c25d050
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.animation;
+
+/**
+ * Listener tests for ValueAnimator.
+ */
+public class ValueAnimatorEventsTest extends EventsTest {
+
+ @Override
+ public void setUp() throws Exception {
+ mAnimator = ValueAnimator.ofFloat(0, 1);
+ super.setUp();
+ }
+
+}
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index 3cb64c7..82345e2 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -44,20 +44,20 @@
public void testAddEntryGrow() throws Exception {
final NetworkStats stats = new NetworkStats(TEST_START, 2);
- assertEquals(0, stats.size);
+ assertEquals(0, stats.size());
assertEquals(2, stats.iface.length);
stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 1L, 2L);
stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 2L, 2L);
- assertEquals(2, stats.size);
+ assertEquals(2, stats.size());
assertEquals(2, stats.iface.length);
stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 3L, 4L);
stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 4L, 4L);
stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 5L, 5L);
- assertEquals(5, stats.size);
+ assertEquals(5, stats.size());
assertTrue(stats.iface.length >= 5);
assertEquals(1L, stats.rx[0]);
diff --git a/core/tests/coretests/src/android/pim/EventRecurrenceTest.java b/core/tests/coretests/src/android/pim/EventRecurrenceTest.java
deleted file mode 100644
index 05000f1..0000000
--- a/core/tests/coretests/src/android/pim/EventRecurrenceTest.java
+++ /dev/null
@@ -1,753 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim;
-
-import android.pim.EventRecurrence.InvalidFormatException;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
-
-import junit.framework.TestCase;
-
-import java.util.Arrays;
-
-/**
- * Test android.pim.EventRecurrence.
- *
- * adb shell am instrument -w -e class android.pim.EventRecurrenceTest \
- * com.android.frameworks.coretests/android.test.InstrumentationTestRunner
- */
-public class EventRecurrenceTest extends TestCase {
-
- @SmallTest
- public void test0() throws Exception {
- verifyRecurType("FREQ=SECONDLY",
- /* int freq */ EventRecurrence.SECONDLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test1() throws Exception {
- verifyRecurType("FREQ=MINUTELY",
- /* int freq */ EventRecurrence.MINUTELY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test2() throws Exception {
- verifyRecurType("FREQ=HOURLY",
- /* int freq */ EventRecurrence.HOURLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test3() throws Exception {
- verifyRecurType("FREQ=DAILY",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test4() throws Exception {
- verifyRecurType("FREQ=WEEKLY",
- /* int freq */ EventRecurrence.WEEKLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test5() throws Exception {
- verifyRecurType("FREQ=MONTHLY",
- /* int freq */ EventRecurrence.MONTHLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test6() throws Exception {
- verifyRecurType("FREQ=YEARLY",
- /* int freq */ EventRecurrence.YEARLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test7() throws Exception {
- // with an until
- verifyRecurType("FREQ=DAILY;UNTIL=112233T223344Z",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ "112233T223344Z",
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test8() throws Exception {
- // with a count
- verifyRecurType("FREQ=DAILY;COUNT=334",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 334,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test9() throws Exception {
- // with a count
- verifyRecurType("FREQ=DAILY;INTERVAL=5000",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 5000,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @SmallTest
- public void test10() throws Exception {
- // verifyRecurType all of the BY* ones with one element
- verifyRecurType("FREQ=DAILY"
- + ";BYSECOND=0"
- + ";BYMINUTE=1"
- + ";BYHOUR=2"
- + ";BYMONTHDAY=30"
- + ";BYYEARDAY=300"
- + ";BYWEEKNO=53"
- + ";BYMONTH=12"
- + ";BYSETPOS=-15"
- + ";WKST=SU",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ new int[]{0},
- /* int[] byminute */ new int[]{1},
- /* int[] byhour */ new int[]{2},
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ new int[]{30},
- /* int[] byyearday */ new int[]{300},
- /* int[] byweekno */ new int[]{53},
- /* int[] bymonth */ new int[]{12},
- /* int[] bysetpos */ new int[]{-15},
- /* int wkst */ EventRecurrence.SU
- );
- }
-
- @SmallTest
- public void test11() throws Exception {
- // verifyRecurType all of the BY* ones with one element
- verifyRecurType("FREQ=DAILY"
- + ";BYSECOND=0,30,59"
- + ";BYMINUTE=0,41,59"
- + ";BYHOUR=0,4,23"
- + ";BYMONTHDAY=-31,-1,1,31"
- + ";BYYEARDAY=-366,-1,1,366"
- + ";BYWEEKNO=-53,-1,1,53"
- + ";BYMONTH=1,12"
- + ";BYSETPOS=1,2,3,4,500,10000"
- + ";WKST=SU",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ new int[]{0, 30, 59},
- /* int[] byminute */ new int[]{0, 41, 59},
- /* int[] byhour */ new int[]{0, 4, 23},
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ new int[]{-31, -1, 1, 31},
- /* int[] byyearday */ new int[]{-366, -1, 1, 366},
- /* int[] byweekno */ new int[]{-53, -1, 1, 53},
- /* int[] bymonth */ new int[]{1, 12},
- /* int[] bysetpos */ new int[]{1, 2, 3, 4, 500, 10000},
- /* int wkst */ EventRecurrence.SU
- );
- }
-
- private static class Check {
- Check(String k, int... v) {
- key = k;
- values = v;
- }
-
- String key;
- int[] values;
- }
-
- // this is a negative verifyRecurType case to verifyRecurType the range of the numbers accepted
- @SmallTest
- public void test12() throws Exception {
- Check[] checks = new Check[]{
- new Check("BYSECOND", -100, -1, 60, 100),
- new Check("BYMINUTE", -100, -1, 60, 100),
- new Check("BYHOUR", -100, -1, 24, 100),
- new Check("BYMONTHDAY", -100, -32, 0, 32, 100),
- new Check("BYYEARDAY", -400, -367, 0, 367, 400),
- new Check("BYWEEKNO", -100, -54, 0, 54, 100),
- new Check("BYMONTH", -100, -5, 0, 13, 100)
- };
-
- for (Check ck : checks) {
- for (int n : ck.values) {
- String recur = "FREQ=DAILY;" + ck.key + "=" + n;
- try {
- EventRecurrence er = new EventRecurrence();
- er.parse(recur);
- fail("Negative verifyRecurType failed. "
- + " parse failed to throw an exception for '"
- + recur + "'");
- } catch (EventRecurrence.InvalidFormatException e) {
- // expected
- }
- }
- }
- }
-
- // verifyRecurType BYDAY
- @SmallTest
- public void test13() throws Exception {
- verifyRecurType("FREQ=DAILY;BYDAY=1SU,-2MO,+33TU,WE,TH,FR,SA",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.SU,
- EventRecurrence.MO,
- EventRecurrence.TU,
- EventRecurrence.WE,
- EventRecurrence.TH,
- EventRecurrence.FR,
- EventRecurrence.SA
- },
- /* int[] bydayNum */ new int[]{1, -2, 33, 0, 0, 0, 0},
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- @Suppress
- // Repro bug #2331761 - this should fail because of the last comma into BYDAY
- public void test14() throws Exception {
- verifyRecurType("FREQ=WEEKLY;WKST=MO;UNTIL=20100129T130000Z;INTERVAL=1;BYDAY=MO,TU,WE,",
- /* int freq */ EventRecurrence.WEEKLY,
- /* String until */ "20100129T130000Z",
- /* int count */ 0,
- /* int interval */ 1,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.MO,
- EventRecurrence.TU,
- EventRecurrence.WE,
- },
- /* int[] bydayNum */ new int[]{0, 0, 0},
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // This test should pass
- public void test15() throws Exception {
- verifyRecurType("FREQ=WEEKLY;WKST=MO;UNTIL=20100129T130000Z;INTERVAL=1;"
- + "BYDAY=MO,TU,WE,TH,FR,SA,SU",
- /* int freq */ EventRecurrence.WEEKLY,
- /* String until */ "20100129T130000Z",
- /* int count */ 0,
- /* int interval */ 1,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.MO,
- EventRecurrence.TU,
- EventRecurrence.WE,
- EventRecurrence.TH,
- EventRecurrence.FR,
- EventRecurrence.SA,
- EventRecurrence.SU
- },
- /* int[] bydayNum */ new int[]{0, 0, 0, 0, 0, 0, 0},
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // Sample coming from RFC2445
- public void test16() throws Exception {
- verifyRecurType("FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1",
- /* int freq */ EventRecurrence.MONTHLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.MO,
- EventRecurrence.TU,
- EventRecurrence.WE,
- EventRecurrence.TH,
- EventRecurrence.FR
- },
- /* int[] bydayNum */ new int[] {0, 0, 0, 0, 0},
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ new int[] { -1 },
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // Sample coming from RFC2445
- public void test17() throws Exception {
- verifyRecurType("FREQ=DAILY;COUNT=10;INTERVAL=2",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 10,
- /* int interval */ 2,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // Sample coming from RFC2445
- public void test18() throws Exception {
- verifyRecurType("FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10",
- /* int freq */ EventRecurrence.YEARLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.SU
- },
- /* int[] bydayNum */ new int[] { -1 },
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ new int[] { 10 },
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // Sample coming from bug #1640517
- public void test19() throws Exception {
- verifyRecurType("FREQ=YEARLY;BYMONTH=3;BYDAY=TH",
- /* int freq */ EventRecurrence.YEARLY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ new int[] {
- EventRecurrence.TH
- },
- /* int[] bydayNum */ new int[] { 0 },
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ new int[] { 3 },
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- // for your copying pleasure
- public void fakeTestXX() throws Exception {
- verifyRecurType("FREQ=DAILY;",
- /* int freq */ EventRecurrence.DAILY,
- /* String until */ null,
- /* int count */ 0,
- /* int interval */ 0,
- /* int[] bysecond */ null,
- /* int[] byminute */ null,
- /* int[] byhour */ null,
- /* int[] byday */ null,
- /* int[] bydayNum */ null,
- /* int[] bymonthday */ null,
- /* int[] byyearday */ null,
- /* int[] byweekno */ null,
- /* int[] bymonth */ null,
- /* int[] bysetpos */ null,
- /* int wkst */ EventRecurrence.MO
- );
- }
-
- private static void cmp(int vlen, int[] v, int[] correct, String name) {
- if ((correct == null && v != null)
- || (correct != null && v == null)) {
- throw new RuntimeException("One is null, one isn't for " + name
- + ": correct=" + Arrays.toString(correct)
- + " actual=" + Arrays.toString(v));
- }
- if ((correct == null && vlen != 0)
- || (vlen != (correct == null ? 0 : correct.length))) {
- throw new RuntimeException("Reported length mismatch for " + name
- + ": correct=" + ((correct == null) ? "null" : correct.length)
- + " actual=" + vlen);
- }
- if (correct == null) {
- return;
- }
- if (v.length < correct.length) {
- throw new RuntimeException("Array length mismatch for " + name
- + ": correct=" + Arrays.toString(correct)
- + " actual=" + Arrays.toString(v));
- }
- for (int i = 0; i < correct.length; i++) {
- if (v[i] != correct[i]) {
- throw new RuntimeException("Array value mismatch for " + name
- + ": correct=" + Arrays.toString(correct)
- + " actual=" + Arrays.toString(v));
- }
- }
- }
-
- private static boolean eq(String a, String b) {
- if ((a == null && b != null) || (a != null && b == null)) {
- return false;
- } else {
- return a == b || a.equals(b);
- }
- }
-
- private static void verifyRecurType(String recur,
- int freq, String until, int count, int interval,
- int[] bysecond, int[] byminute, int[] byhour,
- int[] byday, int[] bydayNum, int[] bymonthday,
- int[] byyearday, int[] byweekno, int[] bymonth,
- int[] bysetpos, int wkst) {
- EventRecurrence eventRecurrence = new EventRecurrence();
- eventRecurrence.parse(recur);
- if (eventRecurrence.freq != freq
- || !eq(eventRecurrence.until, until)
- || eventRecurrence.count != count
- || eventRecurrence.interval != interval
- || eventRecurrence.wkst != wkst) {
- System.out.println("Error... got:");
- print(eventRecurrence);
- System.out.println("expected:");
- System.out.println("{");
- System.out.println(" freq=" + freq);
- System.out.println(" until=" + until);
- System.out.println(" count=" + count);
- System.out.println(" interval=" + interval);
- System.out.println(" wkst=" + wkst);
- System.out.println(" bysecond=" + Arrays.toString(bysecond));
- System.out.println(" byminute=" + Arrays.toString(byminute));
- System.out.println(" byhour=" + Arrays.toString(byhour));
- System.out.println(" byday=" + Arrays.toString(byday));
- System.out.println(" bydayNum=" + Arrays.toString(bydayNum));
- System.out.println(" bymonthday=" + Arrays.toString(bymonthday));
- System.out.println(" byyearday=" + Arrays.toString(byyearday));
- System.out.println(" byweekno=" + Arrays.toString(byweekno));
- System.out.println(" bymonth=" + Arrays.toString(bymonth));
- System.out.println(" bysetpos=" + Arrays.toString(bysetpos));
- System.out.println("}");
- throw new RuntimeException("Mismatch in fields");
- }
- cmp(eventRecurrence.bysecondCount, eventRecurrence.bysecond, bysecond, "bysecond");
- cmp(eventRecurrence.byminuteCount, eventRecurrence.byminute, byminute, "byminute");
- cmp(eventRecurrence.byhourCount, eventRecurrence.byhour, byhour, "byhour");
- cmp(eventRecurrence.bydayCount, eventRecurrence.byday, byday, "byday");
- cmp(eventRecurrence.bydayCount, eventRecurrence.bydayNum, bydayNum, "bydayNum");
- cmp(eventRecurrence.bymonthdayCount, eventRecurrence.bymonthday, bymonthday, "bymonthday");
- cmp(eventRecurrence.byyeardayCount, eventRecurrence.byyearday, byyearday, "byyearday");
- cmp(eventRecurrence.byweeknoCount, eventRecurrence.byweekno, byweekno, "byweekno");
- cmp(eventRecurrence.bymonthCount, eventRecurrence.bymonth, bymonth, "bymonth");
- cmp(eventRecurrence.bysetposCount, eventRecurrence.bysetpos, bysetpos, "bysetpos");
- }
-
- private static void print(EventRecurrence er) {
- System.out.println("{");
- System.out.println(" freq=" + er.freq);
- System.out.println(" until=" + er.until);
- System.out.println(" count=" + er.count);
- System.out.println(" interval=" + er.interval);
- System.out.println(" wkst=" + er.wkst);
- System.out.println(" bysecond=" + Arrays.toString(er.bysecond));
- System.out.println(" bysecondCount=" + er.bysecondCount);
- System.out.println(" byminute=" + Arrays.toString(er.byminute));
- System.out.println(" byminuteCount=" + er.byminuteCount);
- System.out.println(" byhour=" + Arrays.toString(er.byhour));
- System.out.println(" byhourCount=" + er.byhourCount);
- System.out.println(" byday=" + Arrays.toString(er.byday));
- System.out.println(" bydayNum=" + Arrays.toString(er.bydayNum));
- System.out.println(" bydayCount=" + er.bydayCount);
- System.out.println(" bymonthday=" + Arrays.toString(er.bymonthday));
- System.out.println(" bymonthdayCount=" + er.bymonthdayCount);
- System.out.println(" byyearday=" + Arrays.toString(er.byyearday));
- System.out.println(" byyeardayCount=" + er.byyeardayCount);
- System.out.println(" byweekno=" + Arrays.toString(er.byweekno));
- System.out.println(" byweeknoCount=" + er.byweeknoCount);
- System.out.println(" bymonth=" + Arrays.toString(er.bymonth));
- System.out.println(" bymonthCount=" + er.bymonthCount);
- System.out.println(" bysetpos=" + Arrays.toString(er.bysetpos));
- System.out.println(" bysetposCount=" + er.bysetposCount);
- System.out.println("}");
- }
-
-
- /** A list of valid rules. The parser must accept these. */
- private static final String[] GOOD_RRULES = {
- /* extracted wholesale from from RFC 2445 section 4.8.5.4 */
- "FREQ=DAILY;COUNT=10",
- "FREQ=DAILY;UNTIL=19971224T000000Z",
- "FREQ=DAILY;INTERVAL=2",
- "FREQ=DAILY;INTERVAL=10;COUNT=5",
- "FREQ=YEARLY;UNTIL=20000131T090000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA",
- "FREQ=DAILY;UNTIL=20000131T090000Z;BYMONTH=1",
- "FREQ=WEEKLY;COUNT=10",
- "FREQ=WEEKLY;UNTIL=19971224T000000Z",
- "FREQ=WEEKLY;INTERVAL=2;WKST=SU",
- "FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH",
- "FREQ=WEEKLY;COUNT=10;WKST=SU;BYDAY=TU,TH",
- "FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR",
- "FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH",
- "FREQ=MONTHLY;COUNT=10;BYDAY=1FR",
- "FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR",
- "FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU",
- "FREQ=MONTHLY;COUNT=6;BYDAY=-2MO",
- "FREQ=MONTHLY;BYMONTHDAY=-3",
- "FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15",
- "FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1",
- "FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,15",
- "FREQ=MONTHLY;INTERVAL=2;BYDAY=TU",
- "FREQ=YEARLY;COUNT=10;BYMONTH=6,7",
- "FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3",
- "FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200",
- "FREQ=YEARLY;BYDAY=20MO",
- "FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO",
- "FREQ=YEARLY;BYMONTH=3;BYDAY=TH",
- "FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8",
- "FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13",
- "FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13",
- "FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8",
- "FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3",
- "FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2",
- "FREQ=HOURLY;INTERVAL=3;UNTIL=19970902T170000Z",
- "FREQ=MINUTELY;INTERVAL=15;COUNT=6",
- "FREQ=MINUTELY;INTERVAL=90;COUNT=4",
- "FREQ=DAILY;BYHOUR=9,10,11,12,13,14,15,16;BYMINUTE=0,20,40",
- "FREQ=MINUTELY;INTERVAL=20;BYHOUR=9,10,11,12,13,14,15,16",
- "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO",
- "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU",
- /* a few more */
- "FREQ=SECONDLY;BYSECOND=0,15,59",
- "FREQ=MINUTELY;BYMINUTE=0,15,59",
- "FREQ=HOURLY;BYHOUR=+0,+15,+23",
- "FREQ=DAILY;X-WHATEVER=blah", // fails on old parser
- //"freq=daily;wkst=su", // fails on old parser
- };
-
- /** The parser must reject these. */
- private static final String[] BAD_RRULES = {
- "INTERVAL=4;FREQ=YEARLY", // FREQ must come first
- "FREQ=MONTHLY;FREQ=MONTHLY", // can't specify twice
- "FREQ=MONTHLY;COUNT=1;COUNT=1", // can't specify twice
- "FREQ=SECONDLY;BYSECOND=60", // range
- "FREQ=MINUTELY;BYMINUTE=-1", // range
- "FREQ=HOURLY;BYHOUR=24", // range
- "FREQ=YEARLY;BYMONTHDAY=0", // zero not valid
- //"FREQ=YEARLY;COUNT=1;UNTIL=12345", // can't have both COUNT and UNTIL
- //"FREQ=DAILY;UNTIL=19970829T021400e", // invalid date
- };
-
- /**
- * Simple test of good/bad rules.
- */
- @SmallTest
- public void testBasicParse() {
- for (String rule : GOOD_RRULES) {
- EventRecurrence recur = new EventRecurrence();
- recur.parse(rule);
- }
-
- for (String rule : BAD_RRULES) {
- EventRecurrence recur = new EventRecurrence();
- boolean didThrow = false;
-
- try {
- recur.parse(rule);
- } catch (InvalidFormatException ife) {
- didThrow = true;
- }
-
- assertTrue("Expected throw on " + rule, didThrow);
- }
- }
-}
diff --git a/core/tests/coretests/src/android/pim/RecurrenceSetTest.java b/core/tests/coretests/src/android/pim/RecurrenceSetTest.java
deleted file mode 100644
index e5ab179..0000000
--- a/core/tests/coretests/src/android/pim/RecurrenceSetTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim;
-
-import android.content.ContentValues;
-import android.pim.ICalendar;
-import android.pim.RecurrenceSet;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-import android.provider.CalendarContract;
-import junit.framework.TestCase;
-
-/**
- * Test some pim.RecurrenceSet functionality.
- */
-public class RecurrenceSetTest extends TestCase {
-
- // Test a recurrence
- @SmallTest
- public void testRecurrenceSet0() throws Exception {
- String recurrence = "DTSTART;TZID=America/New_York:20080221T070000\n"
- + "DTEND;TZID=America/New_York:20080221T190000\n"
- + "RRULE:FREQ=DAILY;UNTIL=20080222T000000Z\n"
- + "EXDATE:20080222T120000Z";
- verifyPopulateContentValues(recurrence, "FREQ=DAILY;UNTIL=20080222T000000Z", null,
- null, "20080222T120000Z", 1203595200000L, "America/New_York", "P43200S", 0);
- }
-
- // Test 1 day all-day event
- @SmallTest
- public void testRecurrenceSet1() throws Exception {
- String recurrence = "DTSTART;VALUE=DATE:20090821\nDTEND;VALUE=DATE:20090822\n"
- + "RRULE:FREQ=YEARLY;WKST=SU";
- verifyPopulateContentValues(recurrence, "FREQ=YEARLY;WKST=SU", null,
- null, null, 1250812800000L, "UTC", "P1D", 1);
- }
-
- // Test 2 day all-day event
- @SmallTest
- public void testRecurrenceSet2() throws Exception {
- String recurrence = "DTSTART;VALUE=DATE:20090821\nDTEND;VALUE=DATE:20090823\n"
- + "RRULE:FREQ=YEARLY;WKST=SU";
- verifyPopulateContentValues(recurrence, "FREQ=YEARLY;WKST=SU", null,
- null, null, 1250812800000L, "UTC", "P2D", 1);
- }
-
- // run populateContentValues and verify the results
- private void verifyPopulateContentValues(String recurrence, String rrule, String rdate,
- String exrule, String exdate, long dtstart, String tzid, String duration, int allDay)
- throws ICalendar.FormatException {
- ICalendar.Component recurrenceComponent =
- new ICalendar.Component("DUMMY", null /* parent */);
- ICalendar.parseComponent(recurrenceComponent, recurrence);
- ContentValues values = new ContentValues();
- RecurrenceSet.populateContentValues(recurrenceComponent, values);
- Log.d("KS", "values " + values);
-
- assertEquals(rrule, values.get(android.provider.CalendarContract.Events.RRULE));
- assertEquals(rdate, values.get(android.provider.CalendarContract.Events.RDATE));
- assertEquals(exrule, values.get(android.provider.CalendarContract.Events.EXRULE));
- assertEquals(exdate, values.get(android.provider.CalendarContract.Events.EXDATE));
- assertEquals(dtstart, (long) values.getAsLong(CalendarContract.Events.DTSTART));
- assertEquals(tzid, values.get(android.provider.CalendarContract.Events.EVENT_TIMEZONE));
- assertEquals(duration, values.get(android.provider.CalendarContract.Events.DURATION));
- assertEquals(allDay,
- (int) values.getAsInteger(android.provider.CalendarContract.Events.ALL_DAY));
- }
-}
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 6254192..12e5ada 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -155,6 +155,14 @@
}
}
+
+ private int getIDSafe() {
+ if (mAdaptedAllocation != null) {
+ return mAdaptedAllocation.getID();
+ }
+ return getID();
+ }
+
private void updateCacheInfo(Type t) {
mCurrentDimX = t.getX();
mCurrentDimY = t.getY();
@@ -262,7 +270,7 @@
throw new RSIllegalArgumentException("Source must be exactly one usage type.");
}
mRS.validate();
- mRS.nAllocationSyncAll(getID(), srcLocation);
+ mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
}
public void copyFrom(BaseObj[] d) {
@@ -480,7 +488,7 @@
" does not match component size " + eSize + ".");
}
- mRS.nAllocationElementData1D(getID(), xoff, mSelectedLOD,
+ mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD,
component_number, data, data.length);
}
@@ -527,7 +535,7 @@
public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 4, dataSize);
- mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
+ mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
}
/**
* Copy part of an allocation from an array. This variant is
@@ -541,7 +549,7 @@
public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 2, dataSize);
- mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
+ mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
}
/**
* Copy part of an allocation from an array. This variant is
@@ -555,7 +563,7 @@
public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length, dataSize);
- mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
+ mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
}
/**
* Copy part of an allocation from an array. This variant is
@@ -569,7 +577,7 @@
public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 4, dataSize);
- mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
+ mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
}
/**
@@ -638,7 +646,7 @@
* be copied.
*/
public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
- mRS.nAllocationData2D(getID(), off, 0,
+ mRS.nAllocationData2D(getIDSafe(), off, 0,
mSelectedLOD, mSelectedFace.mID,
count, 1, data.getID(), dataOff, 0,
data.mSelectedLOD, data.mSelectedFace.mID);
@@ -674,28 +682,28 @@
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
mRS.validate();
validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
w, h, data, data.length);
}
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
mRS.validate();
validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
w, h, data, data.length * 2);
}
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
mRS.validate();
validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
w, h, data, data.length * 4);
}
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
mRS.validate();
validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
w, h, data, data.length * 4);
}
@@ -715,7 +723,7 @@
Allocation data, int dataXoff, int dataYoff) {
mRS.validate();
validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getID(), xoff, yoff,
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff,
mSelectedLOD, mSelectedFace.mID,
w, h, data.getID(), dataXoff, dataYoff,
data.mSelectedLOD, data.mSelectedFace.mID);
@@ -734,10 +742,16 @@
mRS.validate();
validateBitmapFormat(data);
validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
- mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
}
+ /**
+ * Copy from the Allocation into a Bitmap. The bitmap must
+ * match the dimensions of the Allocation.
+ *
+ * @param b The bitmap to be set from the Allocation.
+ */
public void copyTo(Bitmap b) {
mRS.validate();
validateBitmapFormat(b);
@@ -745,24 +759,52 @@
mRS.nAllocationCopyToBitmap(getID(), b);
}
+ /**
+ * Copy from the Allocation into a byte array. The array must
+ * be at least as large as the Allocation. The allocation must
+ * be of an 8 bit elemental type.
+ *
+ * @param d The array to be set from the Allocation.
+ */
public void copyTo(byte[] d) {
validateIsInt8();
mRS.validate();
mRS.nAllocationRead(getID(), d);
}
+ /**
+ * Copy from the Allocation into a short array. The array must
+ * be at least as large as the Allocation. The allocation must
+ * be of an 16 bit elemental type.
+ *
+ * @param d The array to be set from the Allocation.
+ */
public void copyTo(short[] d) {
validateIsInt16();
mRS.validate();
mRS.nAllocationRead(getID(), d);
}
+ /**
+ * Copy from the Allocation into a int array. The array must be
+ * at least as large as the Allocation. The allocation must be
+ * of an 32 bit elemental type.
+ *
+ * @param d The array to be set from the Allocation.
+ */
public void copyTo(int[] d) {
validateIsInt32();
mRS.validate();
mRS.nAllocationRead(getID(), d);
}
+ /**
+ * Copy from the Allocation into a float array. The array must
+ * be at least as large as the Allocation. The allocation must
+ * be of an 32 bit float elemental type.
+ *
+ * @param d The array to be set from the Allocation.
+ */
public void copyTo(float[] d) {
validateIsFloat32();
mRS.validate();
diff --git a/graphics/java/android/renderscript/AllocationAdapter.java b/graphics/java/android/renderscript/AllocationAdapter.java
index ca5246a..d38f2df 100644
--- a/graphics/java/android/renderscript/AllocationAdapter.java
+++ b/graphics/java/android/renderscript/AllocationAdapter.java
@@ -31,7 +31,8 @@
}
int getID() {
- return mAdaptedAllocation.getID();
+ throw new RSInvalidStateException(
+ "This operation is not supported with adapters at this time.");
}
/**
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index feeb3c3..9725822 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -39,8 +39,6 @@
public:
static sp<ProcessState> self();
- static void setSingleProcess(bool singleProcess);
-
void setContextObject(const sp<IBinder>& object);
sp<IBinder> getContextObject(const sp<IBinder>& caller);
@@ -48,8 +46,6 @@
const String16& name);
sp<IBinder> getContextObject(const String16& name,
const sp<IBinder>& caller);
-
- bool supportsProcesses() const;
void startThreadPool();
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 6ce44fc..9db7364 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -65,6 +65,8 @@
int dispatchDisconnect(va_list args);
int dispatchSetBufferCount(va_list args);
int dispatchSetBuffersGeometry(va_list args);
+ int dispatchSetBuffersDimensions(va_list args);
+ int dispatchSetBuffersFormat(va_list args);
int dispatchSetBuffersTransform(va_list args);
int dispatchSetBuffersTimestamp(va_list args);
int dispatchSetCrop(va_list args);
@@ -73,7 +75,8 @@
int connect(int api);
int disconnect(int api);
int setBufferCount(int bufferCount);
- int setBuffersGeometry(int w, int h, int format);
+ int setBuffersDimensions(int w, int h);
+ int setBuffersFormat(int format);
int setBuffersTransform(int transform);
int setBuffersTimestamp(int64_t timestamp);
int setCrop(Rect const* rect);
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 80b7c1c..8c1c593 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -197,6 +197,12 @@
status_t init(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId, Size videoSize, int32_t frameRate,
bool storeMetaDataInVideoBuffers);
+
+ status_t initWithCameraAccess(
+ const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
+ int32_t cameraId, Size videoSize, int32_t frameRate,
+ bool storeMetaDataInVideoBuffers);
+
status_t isCameraAvailable(const sp<ICamera>& camera,
const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId);
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 904ce2a..77166ed 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -71,7 +71,8 @@
bool mUse32BitOffset;
bool mIsFileSizeLimitExplicitlyRequested;
bool mPaused;
- bool mStarted;
+ bool mStarted; // Writer thread + track threads started successfully
+ bool mWriterThreadStarted; // Only writer thread started successfully
off64_t mOffset;
off_t mMdatOffset;
uint8_t *mMoovBoxBuffer;
@@ -182,6 +183,7 @@
void writeLatitude(int degreex10000);
void writeLongitude(int degreex10000);
void sendSessionSummary();
+ void release();
MPEG4Writer(const MPEG4Writer &);
MPEG4Writer &operator=(const MPEG4Writer &);
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 2d4e10d..7264ac4 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -43,8 +43,6 @@
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
-static bool gSingleProcess = false;
-
// ---------------------------------------------------------------------------
@@ -82,12 +80,6 @@
return gProcess;
}
-void ProcessState::setSingleProcess(bool singleProcess)
-{
- gSingleProcess = singleProcess;
-}
-
-
void ProcessState::setContextObject(const sp<IBinder>& object)
{
setContextObject(object, String16("default"));
@@ -95,11 +87,7 @@
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
{
- if (supportsProcesses()) {
- return getStrongProxyForHandle(0);
- } else {
- return getContextObject(String16("default"), caller);
- }
+ return getStrongProxyForHandle(0);
}
void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
@@ -144,11 +132,6 @@
return object;
}
-bool ProcessState::supportsProcesses() const
-{
- return mDriverFD >= 0;
-}
-
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
@@ -169,24 +152,19 @@
AutoMutex _l(mLock);
mBinderContextCheckFunc = checkFunc;
mBinderContextUserData = userData;
- if (mDriverFD >= 0) {
- int dummy = 0;
+
+ int dummy = 0;
#if defined(HAVE_ANDROID_OS)
- status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+ status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
#else
- status_t result = INVALID_OPERATION;
+ status_t result = INVALID_OPERATION;
#endif
- if (result == 0) {
- mManagesContexts = true;
- } else if (result == -1) {
- mBinderContextCheckFunc = NULL;
- mBinderContextUserData = NULL;
- LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
- }
- } else {
- // If there is no driver, our only world is the local
- // process so we can always become the context manager there.
+ if (result == 0) {
mManagesContexts = true;
+ } else if (result == -1) {
+ mBinderContextCheckFunc = NULL;
+ mBinderContextUserData = NULL;
+ LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
}
}
return mManagesContexts;
@@ -322,10 +300,6 @@
static int open_driver()
{
- if (gSingleProcess) {
- return -1;
- }
-
int fd = open("/dev/binder", O_RDWR);
if (fd >= 0) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
@@ -386,9 +360,8 @@
mDriverFD = -1;
#endif
}
- if (mDriverFD < 0) {
- // Need to run without the driver, starting our own thread pool.
- }
+
+ LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
ProcessState::~ProcessState()
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index b9b2310..e203035 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -254,6 +254,12 @@
case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
res = dispatchSetBuffersTimestamp(args);
break;
+ case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+ res = dispatchSetBuffersDimensions(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ res = dispatchSetBuffersFormat(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -290,7 +296,22 @@
int w = va_arg(args, int);
int h = va_arg(args, int);
int f = va_arg(args, int);
- return setBuffersGeometry(w, h, f);
+ int err = setBuffersDimensions(w, h);
+ if (err != 0) {
+ return err;
+ }
+ return setBuffersFormat(f);
+}
+
+int SurfaceTextureClient::dispatchSetBuffersDimensions(va_list args) {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ return setBuffersDimensions(w, h);
+}
+
+int SurfaceTextureClient::dispatchSetBuffersFormat(va_list args) {
+ int f = va_arg(args, int);
+ return setBuffersFormat(f);
}
int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
@@ -390,12 +411,12 @@
return err;
}
-int SurfaceTextureClient::setBuffersGeometry(int w, int h, int format)
+int SurfaceTextureClient::setBuffersDimensions(int w, int h)
{
- LOGV("SurfaceTextureClient::setBuffersGeometry");
+ LOGV("SurfaceTextureClient::setBuffersDimensions");
Mutex::Autolock lock(mMutex);
- if (w<0 || h<0 || format<0)
+ if (w<0 || h<0)
return BAD_VALUE;
if ((w && !h) || (!w && h))
@@ -403,7 +424,6 @@
mReqWidth = w;
mReqHeight = h;
- mReqFormat = format;
status_t err = mSurfaceTexture->setCrop(Rect(0, 0));
LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s", strerror(-err));
@@ -411,6 +431,19 @@
return err;
}
+int SurfaceTextureClient::setBuffersFormat(int format)
+{
+ LOGV("SurfaceTextureClient::setBuffersFormat");
+ Mutex::Autolock lock(mMutex);
+
+ if (format<0)
+ return BAD_VALUE;
+
+ mReqFormat = format;
+
+ return NO_ERROR;
+}
+
int SurfaceTextureClient::setBuffersTransform(int transform)
{
LOGV("SurfaceTextureClient::setBuffersTransform");
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 4393504..9c10c75 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -299,6 +299,7 @@
{
switch (operation) {
case NATIVE_WINDOW_SET_USAGE:
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
case NATIVE_WINDOW_CONNECT:
case NATIVE_WINDOW_DISCONNECT:
break;
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 289c826..87ae3d5 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -290,7 +290,7 @@
void* VectorImpl::editItemLocation(size_t index)
{
LOG_ASSERT(index<capacity(),
- "[%p] itemLocation: index=%d, capacity=%d, count=%d",
+ "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
this, (int)index, (int)capacity(), (int)mCount);
void* buffer = editArrayImpl();
@@ -302,7 +302,7 @@
const void* VectorImpl::itemLocation(size_t index) const
{
LOG_ASSERT(index<capacity(),
- "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
+ "[%p] itemLocation: index=%d, capacity=%d, count=%d",
this, (int)index, (int)capacity(), (int)mCount);
const void* buffer = arrayImpl();
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 18742ea..e8ddd2d 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -101,6 +101,8 @@
* Java MyMediaScanner handleStringTag.
* Once MediaScanner processFile returns, an entry is inserted in to the database.
*
+ * The MediaScanner class is not thread-safe, so it should only be used in a single threaded manner.
+ *
* {@hide}
*/
public class MediaScanner
@@ -1174,10 +1176,6 @@
mPlaylistsUri = Playlists.getContentUri(volumeName);
mCaseInsensitivePaths = true;
- if (!Process.supportsProcesses()) {
- // Simulator uses host file system, so it should be case sensitive.
- mCaseInsensitivePaths = false;
- }
}
}
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 9151799..d0d2d1e 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -45,7 +45,6 @@
jfieldID context;
};
static fields_t fields;
-static Mutex sLock;
class MyMediaScannerClient : public MediaScannerClient
{
@@ -159,13 +158,11 @@
return ((JNIEnv *)env)->ExceptionCheck();
}
-// Call this method with sLock hold
static MediaScanner *getNativeScanner_l(JNIEnv* env, jobject thiz)
{
return (MediaScanner *) env->GetIntField(thiz, fields.context);
}
-// Call this method with sLock hold
static void setNativeScanner_l(JNIEnv* env, jobject thiz, MediaScanner *s)
{
env->SetIntField(thiz, fields.context, (int)s);
@@ -176,7 +173,6 @@
JNIEnv *env, jobject thiz, jstring path, jobject client)
{
LOGV("processDirectory");
- Mutex::Autolock l(sLock);
MediaScanner *mp = getNativeScanner_l(env, thiz);
if (mp == NULL) {
jniThrowException(env, kRunTimeException, "No scanner available");
@@ -243,7 +239,6 @@
JNIEnv *env, jobject thiz, jstring locale)
{
LOGV("setLocale");
- Mutex::Autolock l(sLock);
MediaScanner *mp = getNativeScanner_l(env, thiz);
if (mp == NULL) {
jniThrowException(env, kRunTimeException, "No scanner available");
@@ -268,7 +263,6 @@
JNIEnv *env, jobject thiz, jobject fileDescriptor)
{
LOGV("extractAlbumArt");
- Mutex::Autolock l(sLock);
MediaScanner *mp = getNativeScanner_l(env, thiz);
if (mp == NULL) {
jniThrowException(env, kRunTimeException, "No scanner available");
@@ -339,7 +333,6 @@
android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz)
{
LOGV("native_finalize");
- Mutex::Autolock l(sLock);
MediaScanner *mp = getNativeScanner_l(env, thiz);
if (mp == 0) {
return;
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index a3e76d9..a9689bc 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -130,10 +130,43 @@
return ret;
}
+int Effect_ProcessReverse(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
+{
+ int ret = init();
+ if (ret < 0) {
+ return ret;
+ }
+ effect_entry_t *fx = (effect_entry_t *)self;
+ pthread_mutex_lock(&gLibLock);
+ if (fx->lib == NULL) {
+ pthread_mutex_unlock(&gLibLock);
+ return -EPIPE;
+ }
+ pthread_mutex_lock(&fx->lib->lock);
+ pthread_mutex_unlock(&gLibLock);
+
+ if ((*fx->subItfe)->process_reverse != NULL) {
+ ret = (*fx->subItfe)->process_reverse(fx->subItfe, inBuffer, outBuffer);
+ } else {
+ ret = -ENOSYS;
+ }
+ pthread_mutex_unlock(&fx->lib->lock);
+ return ret;
+}
+
+
const struct effect_interface_s gInterface = {
Effect_Process,
Effect_Command,
- Effect_GetDescriptor
+ Effect_GetDescriptor,
+ NULL
+};
+
+const struct effect_interface_s gInterfaceWithReverse = {
+ Effect_Process,
+ Effect_Command,
+ Effect_GetDescriptor,
+ Effect_ProcessReverse
};
/////////////////////////////////////////////////
@@ -266,7 +299,13 @@
// add entry to effect list
fx = (effect_entry_t *)malloc(sizeof(effect_entry_t));
fx->subItfe = itfe;
- fx->itfe = (struct effect_interface_s *)&gInterface;
+ if ((*itfe)->process_reverse != NULL) {
+ fx->itfe = (struct effect_interface_s *)&gInterfaceWithReverse;
+ LOGV("EffectCreate() gInterfaceWithReverse");
+ } else {
+ fx->itfe = (struct effect_interface_s *)&gInterface;
+ LOGV("EffectCreate() gInterface");
+ }
fx->lib = l;
e = (list_elem_t *)malloc(sizeof(list_elem_t));
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 21c451f..efa1c45 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -3231,7 +3231,8 @@
const struct effect_interface_s gLvmEffectInterface = {
Effect_process,
Effect_command,
- Effect_getDescriptor
+ Effect_getDescriptor,
+ NULL,
}; /* end gLvmEffectInterface */
audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 2727375..663f8ff 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -2134,7 +2134,8 @@
const struct effect_interface_s gReverbInterface = {
Reverb_process,
Reverb_command,
- Reverb_getDescriptor
+ Reverb_getDescriptor,
+ NULL,
}; /* end gReverbInterface */
audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
index c2ffce5..b22ebec 100644
--- a/media/libeffects/testlibs/EffectEqualizer.cpp
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -736,7 +736,8 @@
const struct effect_interface_s gEqualizerInterface = {
Equalizer_process,
Equalizer_command,
- Equalizer_getDescriptor
+ Equalizer_getDescriptor,
+ NULL
};
diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c
index 02762c9..405f908 100644
--- a/media/libeffects/testlibs/EffectReverb.c
+++ b/media/libeffects/testlibs/EffectReverb.c
@@ -27,7 +27,8 @@
const struct effect_interface_s gReverbInterface = {
Reverb_Process,
Reverb_Command,
- Reverb_GetDescriptor
+ Reverb_GetDescriptor,
+ NULL
};
// Google auxiliary environmental reverb UUID: 1f0ae2e0-4ef7-11df-bc09-0002a5d5c51b
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index aeebd4d..3c3af8f 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -450,7 +450,8 @@
const struct effect_interface_s gVisualizerInterface = {
Visualizer_process,
Visualizer_command,
- Visualizer_getDescriptor
+ Visualizer_getDescriptor,
+ NULL,
};
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index ed8149a..c7e7ced 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -158,12 +158,10 @@
mVideoSize.width = -1;
mVideoSize.height = -1;
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
mInitCheck = init(camera, proxy, cameraId,
videoSize, frameRate,
storeMetaDataInVideoBuffers);
if (mInitCheck != OK) releaseCamera();
- IPCThreadState::self()->restoreCallingIdentity(token);
}
status_t CameraSource::initCheck() const {
@@ -463,6 +461,22 @@
bool storeMetaDataInVideoBuffers) {
status_t err = OK;
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ err = initWithCameraAccess(camera, proxy, cameraId,
+ videoSize, frameRate,
+ storeMetaDataInVideoBuffers);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ return err;
+}
+
+status_t CameraSource::initWithCameraAccess(
+ const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy,
+ int32_t cameraId,
+ Size videoSize,
+ int32_t frameRate,
+ bool storeMetaDataInVideoBuffers) {
+ status_t err = OK;
if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
LOGE("Camera connection could not be established.");
@@ -525,6 +539,11 @@
CameraSource::~CameraSource() {
if (mStarted) {
stop();
+ } else if (mInitCheck == OK) {
+ // Camera is initialized but because start() is never called,
+ // the lock on Camera is never released(). This makes sure
+ // Camera's lock is released in this case.
+ releaseCamera();
}
}
@@ -571,6 +590,7 @@
void CameraSource::releaseCamera() {
LOGV("releaseCamera");
if (mCamera != 0) {
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
LOGV("Camera was cold when we started, stopping preview");
mCamera->stopPreview();
@@ -580,6 +600,7 @@
mCamera->unlock();
}
mCamera.clear();
+ IPCThreadState::self()->restoreCallingIdentity(token);
}
if (mCameraRecordingProxy != 0) {
mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index f075699d..eaad2c3 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -246,6 +246,7 @@
mIsFileSizeLimitExplicitlyRequested(false),
mPaused(false),
mStarted(false),
+ mWriterThreadStarted(false),
mOffset(0),
mMdatOffset(0),
mEstimatedMoovBoxSize(0),
@@ -269,6 +270,7 @@
mIsFileSizeLimitExplicitlyRequested(false),
mPaused(false),
mStarted(false),
+ mWriterThreadStarted(false),
mOffset(0),
mMdatOffset(0),
mEstimatedMoovBoxSize(0),
@@ -538,6 +540,9 @@
void MPEG4Writer::stopWriterThread() {
LOGD("Stopping writer thread");
+ if (!mWriterThreadStarted) {
+ return;
+ }
{
Mutex::Autolock autolock(mLock);
@@ -548,6 +553,7 @@
void *dummy;
pthread_join(mThread, &dummy);
+ mWriterThreadStarted = false;
LOGD("Writer thread stopped");
}
@@ -603,10 +609,25 @@
writeInt32(0x40000000); // w
}
+void MPEG4Writer::release() {
+ close(mFd);
+ mFd = -1;
+ mInitCheck = NO_INIT;
+ mStarted = false;
+}
status_t MPEG4Writer::stop() {
if (mInitCheck != OK) {
return OK;
+ } else {
+ if (!mWriterThreadStarted ||
+ !mStarted) {
+ if (mWriterThreadStarted) {
+ stopWriterThread();
+ }
+ release();
+ return OK;
+ }
}
status_t err = OK;
@@ -637,10 +658,7 @@
// Do not write out movie header on error.
if (err != OK) {
- close(mFd);
- mFd = -1;
- mInitCheck = NO_INIT;
- mStarted = false;
+ release();
return err;
}
@@ -688,11 +706,7 @@
CHECK(mBoxes.empty());
- close(mFd);
- mFd = -1;
- mInitCheck = NO_INIT;
- mStarted = false;
-
+ release();
return err;
}
@@ -1415,6 +1429,7 @@
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&mThread, &attr, ThreadWrapper, this);
pthread_attr_destroy(&attr);
+ mWriterThreadStarted = true;
return OK;
}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 7d5d010..ba5d29a 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -367,7 +367,12 @@
if (cnx->egl.eglGetConfigAttrib(iDpy,
iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
if (format != 0) {
- native_window_set_buffers_geometry(window, 0, 0, format);
+ int err = native_window_set_buffers_format(window, format);
+ if (err != 0) {
+ LOGE("error setting native window pixel format: %s (%d)",
+ strerror(-err), err);
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
}
}
diff --git a/opengl/specs/EGL_ANDROID_blob_cache.txt b/opengl/specs/EGL_ANDROID_blob_cache.txt
new file mode 100644
index 0000000..55dc900
--- /dev/null
+++ b/opengl/specs/EGL_ANDROID_blob_cache.txt
@@ -0,0 +1,208 @@
+Name
+
+ ANDROID_blob_cache
+
+Name Strings
+
+ EGL_ANDROID_blob_cache
+
+Contributors
+
+ Jamie Gennis
+
+Contact
+
+ Jamie Gennis, Google Inc. (jgennis 'at' google.com)
+
+Status
+
+ Draft.
+
+Version
+
+ Version 1, April 22, 2011
+
+Number
+
+ EGL Extension #XXX
+
+Dependencies
+
+ Requires EGL 1.0
+
+ This extension is written against the wording of the EGL 1.4 Specification
+
+Overview
+
+ Shader compilation and optimization has been a troublesome aspect of OpenGL
+ programming for a long time. It can consume seconds of CPU cycles during
+ application start-up. Additionally, state-based re-compiles done
+ internally by the drivers add an unpredictable element to application
+ performance tuning, often leading to occasional pauses in otherwise smooth
+ animations.
+
+ This extension provides a mechanism through which client API
+ implementations may cache shader binaries after they are compiled. It may
+ then retrieve those cached shaders during subsequent executions of the same
+ program. The management of the cache is handled by the application (or
+ middleware), allowing it to be tuned to a particular platform or
+ environment.
+
+ While the focus of this extension is on providing a persistent cache for
+ shader binaries, it may also be useful for caching other data. This is
+ perfectly acceptable, but the guarantees provided (or lack thereof) were
+ designed around the shader use case.
+
+ Note that although this extension is written as if the application
+ implements the caching functionality, on the Android OS it is implemented
+ as part of the Android EGL module. This extension is not exposed to
+ applications on Android, but will be used automatically in every
+ application that uses EGL if it is supported by the underlying
+ device-specific EGL implementation.
+
+New Types
+
+ /*
+ * EGLsizei is a signed integer type for representing the size of a memory
+ * buffer.
+ */
+ #include <khrplatform.h>
+ typedef khronos_ssize_t EGLsizei;
+
+ /*
+ * EGLSetBlobFunc is a pointer to an application-provided function that a
+ * client API implementation may use to insert a key/value pair into the
+ * cache.
+ */
+ typedef void (*EGLSetBlobFunc) (const void* key, EGLsizei keySize,
+ const void* value, EGLsizei valueSize)
+
+ /*
+ * EGLGetBlobFunc is a pointer to an application-provided function that a
+ * client API implementation may use to retrieve a cached value from the
+ * cache.
+ */
+ typedef EGLsizei (*EGLGetBlobFunc) (const void* key, EGLsizei keySize,
+ void* value, EGLsizei valueSize)
+
+New Procedures and Functions
+
+ void eglSetBlobCacheFuncs(EGLDisplay dpy,
+ EGLSetBlobFunc set,
+ EGLGetBlobFunc get);
+
+New Tokens
+
+ None.
+
+Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
+
+ Add a new subsection after Section 3.8, page 50
+ (Synchronization Primitives)
+
+ "3.9 Persistent Caching
+
+ In order to facilitate persistent caching of internal client API state that
+ is slow to compute or collect, the application may specify callback
+ function pointers through which the client APIs can request data be cached
+ and retrieved. The command
+
+ void eglSetBlobCacheFuncs(EGLDisplay dpy,
+ EGLSetBlobFunc set, EGLGetBlobFunc get);
+
+ sets the callback function pointers that client APIs associated with
+ display <dpy> can use to interact with caching functionality provided by
+ the application. <set> points to a function that inserts a new value into
+ the cache and associates it with the given key. <get> points to a function
+ that retrieves from the cache the value associated with a given key. The
+ semantics of these callback functions are described in Section 3.9.1 (Cache
+ Operations).
+
+ Cache functions may only be specified once during the lifetime of an
+ EGLDisplay. The <set> and <get> functions may be called at any time and
+ from any thread from the time at which eglSetBlobCacheFuncs is called until
+ the time that the last resource associated with <dpy> is deleted and <dpy>
+ itself is terminated. Concurrent calls to these functions from different
+ threads is also allowed.
+
+ If eglSetBlobCacheFuncs generates an error then all client APIs must behave
+ as though eglSetBlobCacheFuncs was not called for the display <dpy>. If
+ <set> or <get> is NULL then an EGL_BAD_PARAMETER error is generated. If a
+ successful eglSetBlobCacheFuncs call was already made for <dpy> and the
+ display has not since been terminated then an EGL_BAD_PARAMETER error is
+ generated.
+
+ 3.9.1 Cache Operations
+
+ To insert a new binary value into the cache and associate it with a given
+ key, a client API implementation can call the application-provided callback
+ function
+
+ void (*set) (const void* key, EGLsizei keySize, const void* value,
+ EGLsizei valueSize)
+
+ <key> and <value> are pointers to the beginning of the key and value,
+ respectively, that are to be inserted. <keySize> and <valueSize> specify
+ the size in bytes of the data pointed to by <key> and <value>,
+ respectively.
+
+ No guarantees are made as to whether a given key/value pair is present in
+ the cache after the set call. If a different value has been associated
+ with the given key in the past then it is undefined which value, if any, is
+ associated with the key after the set call. Note that while there are no
+ guarantees, the cache implementation should attempt to cache the most
+ recently set value for a given key.
+
+ To retrieve the binary value associated with a given key from the cache, a
+ client API implementation can call the application-provided callback
+ function
+
+ EGLsizei (*get) (const void* key, EGLsizei keySize, void* value,
+ EGLsizei valueSize)
+
+ <key> is a pointer to the beginning of the key. <keySize> specifies the
+ size in bytes of the binary key pointed to by <key>. If the cache contains
+ a value associated with the given key then the size of that binary value in
+ bytes is returned. Otherwise 0 is returned.
+
+ If the cache contains a value for the given key and its size in bytes is
+ less than or equal to <valueSize> then the value is written to the memory
+ pointed to by <value>. Otherwise nothing is written to the memory pointed
+ to by <value>.
+
+Issues
+
+ 1. How should errors be handled in the callback functions?
+
+ RESOLVED: No guarantees are made about the presence of values in the cache,
+ so there should not be a need to return error information to the client API
+ implementation. The cache implementation can simply drop a value if it
+ encounters an error during the 'set' callback. Similarly, it can simply
+ return 0 if it encouters an error in a 'get' callback.
+
+ 2. When a client API driver gets updated, that may need to invalidate
+ previously cached entries. How can the driver handle this situation?
+
+ RESPONSE: There are a number of ways the driver can handle this situation.
+ The recommended way is to include the driver version in all cache keys.
+ That way each driver version will use a set of cache keys that are unique
+ to that version, and conflicts should never occur. Updating the driver
+ could then leave a number of values in the cache that will never be
+ requested again. If needed, the cache implementation can handle those
+ values in some way, but the driver does not need to take any special
+ action.
+
+ 3. How much data can be stored in the cache?
+
+ RESPONSE: This is entirely dependent upon the cache implementation.
+ Presumably it will be tuned to store enough data to be useful, but not
+ enough to become problematic. :)
+
+Revision History
+
+#2 (Jamie Gennis, April 25, 2011)
+ - Swapped the order of the size and pointer arguments to the get and set
+ functions.
+
+#1 (Jamie Gennis, April 22, 2011)
+ - Initial draft.
diff --git a/opengl/specs/EGL_ANDROID_recordable.txt b/opengl/specs/EGL_ANDROID_recordable.txt
new file mode 100644
index 0000000..cf44465
--- /dev/null
+++ b/opengl/specs/EGL_ANDROID_recordable.txt
@@ -0,0 +1,113 @@
+Name
+
+ ANDROID_recordable
+
+Name Strings
+
+ EGL_ANDROID_recordable
+
+Contributors
+
+ Jamie Gennis
+
+Contact
+
+ Jamie Gennis, Google Inc. (jgennis 'at' google.com)
+
+Status
+
+ Draft.
+
+Version
+
+ Version 1, July 8, 2011
+
+Number
+
+ EGL Extension #XXX
+
+Dependencies
+
+ Requires EGL 1.0
+
+ This extension is written against the wording of the EGL 1.4 Specification
+
+Overview
+
+ Android supports a number of different ANativeWindow implementations that
+ can be used to create an EGLSurface. One implementation, which records the
+ rendered image as a video each time eglSwapBuffers gets called, may have
+ some device-specific restrictions. Because of this, some EGLConfigs may be
+ incompatible with these ANativeWindows. This extension introduces a new
+ boolean EGLConfig attribute that indicates whether the EGLConfig supports
+ rendering to an ANativeWindow that records images to a video.
+
+New Types
+
+ None.
+
+New Procedures and Functions
+
+ None.
+
+New Tokens
+
+ Accepted by the <attribute> parameter of eglGetConfigAttrib and
+ the <attrib_list> parameter of eglChooseConfig:
+
+ EGL_RECORDABLE_ANDROID 0xXXXX
+
+Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
+
+ Section 3.4, Configuration Management, add a row to Table 3.1.
+
+ Attribute Type Notes
+ ---------------------- ------- --------------------------
+ EGL_RECORDABLE_ANDROID boolean whether video recording is
+ supported
+
+ Section 3.4, Configuration Management, add a row to Table 3.4.
+
+ Attribute Default Selection Sort Sort
+ Criteria Order Priority
+ ---------------------- ------------- --------- ----- --------
+ EGL_RECORDABLE_ANDROID EGL_DONT_CARE Exact None
+
+ Section 3.4, Configuration Management, add a paragraph at the end of the
+ subsection titled Other EGLConfig Attribute Descriptions.
+
+ EGL_RECORDABLE_ANDROID is a boolean indicating whether the config may
+ be used to create an EGLSurface from an ANativeWindow that is a video
+ recorder as indicated by the NATIVE_WINDOW_IS_VIDEO_RECORDER query on
+ the ANativeWindow.
+
+ Section 3.4.1, Querying Configurations, change the last paragraph as follow
+
+ EGLConfigs are not sorted with respect to the parameters
+ EGL_BIND_TO_TEXTURE_RGB, EGL_BIND_TO_TEXTURE_RGBA, EGL_CONFORMANT,
+ EGL_LEVEL, EGL_NATIVE_RENDERABLE, EGL_MAX_SWAP_INTERVAL,
+ EGL_MIN_SWAP_INTERVAL, EGL_RENDERABLE_TYPE, EGL_SURFACE_TYPE,
+ EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RED_VALUE,
+ EGL_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_BLUE_VALUE, and
+ EGL_RECORDABLE_ANDROID.
+
+Issues
+
+ 1. Should this functionality be exposed as a new attribute or as a bit in
+ the EGL_SURFACE_TYPE bitfield?
+
+ RESOLVED: It should be a new attribute. It does not make sense to use up a
+ bit in the limit-size bitfield for a platform-specific extension.
+
+ 2. How should the new attribute affect the sorting of EGLConfigs?
+
+ RESOLVED: It should not affect sorting. Some implementations may not have
+ any drawback associated with using a recordable EGLConfig. Such
+ implementations should not have to double-up some of their configs to one sort earlier than .
+ Implementations that do have drawbacks can use the existing caveat
+ mechanism to report this drawback to the client.
+
+Revision History
+
+#1 (Jamie Gennis, July 8, 2011)
+ - Initial draft.
diff --git a/opengl/specs/README b/opengl/specs/README
new file mode 100644
index 0000000..2fa2587
--- /dev/null
+++ b/opengl/specs/README
@@ -0,0 +1,12 @@
+This directory contains OpenGL ES and EGL extension specifications that have
+been or are being defined for Android.
+
+The table below tracks usage of EGL enumerant values that have been reserved
+for use by Android extensions.
+
+ Value Extension
+---------------- ----------------------------------
+0x3140 EGL_ANDROID_image_native_buffer
+0x3141 (unused)
+0x3142 EGL_ANDROID_recordable
+0x3143 - 0x314F (unused)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 826ac92..dedbe5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -785,7 +785,7 @@
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
mBluetoothEnabled = state == BluetoothAdapter.STATE_ON;
} else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
- int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
BluetoothAdapter.STATE_DISCONNECTED);
if (state == BluetoothAdapter.STATE_CONNECTED) {
iconId = R.drawable.stat_sys_data_bluetooth_connected;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 7f6327d..dff0556 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1555,9 +1555,12 @@
// We restore the panel if it was last open; we skip it if it
// now is open, to avoid a race condition if the user immediately
// opens it when we are resuming.
- if ((st != null) && !st.isOpen && st.wasLastOpen) {
- st.isInExpandedMode = st.wasLastExpanded;
- openPanel(st, null);
+ if (st != null) {
+ st.applyFrozenState();
+ if (!st.isOpen && st.wasLastOpen) {
+ st.isInExpandedMode = st.wasLastExpanded;
+ openPanel(st, null);
+ }
}
}
}
@@ -2235,6 +2238,11 @@
}
mActionModePopup = null;
}
+
+ PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+ if (st != null && st.menu != null) {
+ st.menu.close();
+ }
}
@Override
@@ -3046,46 +3054,33 @@
getIconMenuView(cb); // Need this initialized to know where our offset goes
- boolean init = false;
if (expandedMenuPresenter == null) {
expandedMenuPresenter = new ListMenuPresenter(
com.android.internal.R.layout.list_menu_item_layout,
com.android.internal.R.style.Theme_ExpandedMenu);
expandedMenuPresenter.setCallback(cb);
+ expandedMenuPresenter.setId(com.android.internal.R.id.list_menu_presenter);
menu.addMenuPresenter(expandedMenuPresenter);
- init = true;
}
expandedMenuPresenter.setItemIndexOffset(iconMenuPresenter.getNumActualItemsShown());
MenuView result = expandedMenuPresenter.getMenuView(decorView);
- if (init && frozenMenuState != null) {
- expandedMenuPresenter.restoreHierarchyState(frozenMenuState);
- // Once we initialize the expanded menu we're done with the frozen state
- // since we will have also restored any icon menu state.
- frozenMenuState = null;
- }
-
return result;
}
MenuView getIconMenuView(MenuPresenter.Callback cb) {
if (menu == null) return null;
- boolean init = false;
if (iconMenuPresenter == null) {
iconMenuPresenter = new IconMenuPresenter();
iconMenuPresenter.setCallback(cb);
+ iconMenuPresenter.setId(com.android.internal.R.id.icon_menu_presenter);
menu.addMenuPresenter(iconMenuPresenter);
- init = true;
}
MenuView result = iconMenuPresenter.getMenuView(decorView);
- if (init && frozenMenuState != null) {
- iconMenuPresenter.restoreHierarchyState(frozenMenuState);
- }
-
return result;
}
@@ -3097,12 +3092,7 @@
if (menu != null) {
savedState.menuState = new Bundle();
- if (iconMenuPresenter != null) {
- iconMenuPresenter.saveHierarchyState(savedState.menuState);
- }
- if (expandedMenuPresenter != null) {
- expandedMenuPresenter.saveHierarchyState(savedState.menuState);
- }
+ menu.savePresenterStates(savedState.menuState);
}
return savedState;
@@ -3127,6 +3117,13 @@
decorView = null;
}
+ void applyFrozenState() {
+ if (menu != null && frozenMenuState != null) {
+ menu.restorePresenterStates(frozenMenuState);
+ frozenMenuState = null;
+ }
+ }
+
private static class SavedState implements Parcelable {
int featureId;
boolean isOpen;
diff --git a/services/camera/libcameraservice/CameraHardwareStub.h b/services/camera/libcameraservice/CameraHardwareStub.h
index 9b66a76..c6d8756 100644
--- a/services/camera/libcameraservice/CameraHardwareStub.h
+++ b/services/camera/libcameraservice/CameraHardwareStub.h
@@ -73,14 +73,7 @@
CameraHardwareStub* mHardware;
public:
PreviewThread(CameraHardwareStub* hw) :
-#ifdef SINGLE_PROCESS
- // In single process mode this thread needs to be a java thread,
- // since we won't be calling through the binder.
- Thread(true),
-#else
- Thread(false),
-#endif
- mHardware(hw) { }
+ Thread(false), mHardware(hw) { }
virtual void onFirstRef() {
run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
}
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 10b9083..da9b55c 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -3154,11 +3154,9 @@
mLastHoverWindow = NULL;
}
- mWindows.clear();
-
// Loop over new windows and rebuild the necessary window pointers for
// tracking focus and touch.
- mWindows.appendVector(inputWindows);
+ mWindows = inputWindows;
size_t numWindows = mWindows.size();
for (size_t i = 0; i < numWindows; i++) {
@@ -4560,8 +4558,7 @@
split = other.split;
deviceId = other.deviceId;
source = other.source;
- windows.clear();
- windows.appendVector(other.windows);
+ windows = other.windows;
}
void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window,
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 158c778..0b15221 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -1072,7 +1072,7 @@
throw new IllegalArgumentException("packageName and uid don't match packageName="
+ packageName);
}
- if (callingUid != packageUid && Process.supportsProcesses()) {
+ if (callingUid != packageUid) {
throw new IllegalArgumentException("packageName and uid don't match packageName="
+ packageName);
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 2d55433..18d393f 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -531,10 +531,7 @@
mImeSwitcherNotification.sound = null;
mImeSwitcherNotification.vibrate = null;
Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
- | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mImeSwitchPendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+ mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
com.android.internal.R.bool.show_ongoing_ime_switcher);
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index da1bf83..829df39 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -77,11 +77,15 @@
/** Path to {@code /proc/uid_stat}. */
@Deprecated
- private final File mProcStatsUidstat;
+ private final File mStatsUid;
+ /** Path to {@code /proc/net/dev}. */
+ private final File mStatsIface;
/** Path to {@code /proc/net/xt_qtaguid/stats}. */
- private final File mProcStatsNetfilter;
+ private final File mStatsXtUid;
+ /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
+ private final File mStatsXtIface;
- /** {@link #mProcStatsNetfilter} headers. */
+ /** {@link #mStatsXtUid} headers. */
private static final String KEY_IFACE = "iface";
private static final String KEY_TAG_HEX = "acct_tag_hex";
private static final String KEY_UID = "uid_tag_int";
@@ -137,8 +141,10 @@
mContext = context;
mObservers = new ArrayList<INetworkManagementEventObserver>();
- mProcStatsUidstat = new File(procRoot, "uid_stat");
- mProcStatsNetfilter = new File(procRoot, "net/xt_qtaguid/stats");
+ mStatsUid = new File(procRoot, "uid_stat");
+ mStatsIface = new File(procRoot, "net/dev");
+ mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
+ mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
return;
@@ -161,9 +167,12 @@
}
// @VisibleForTesting
- public static NetworkManagementService createForTest(Context context, File procRoot) {
+ public static NetworkManagementService createForTest(
+ Context context, File procRoot, boolean bandwidthControlEnabled) {
// TODO: eventually connect with mock netd
- return new NetworkManagementService(context, procRoot);
+ final NetworkManagementService service = new NetworkManagementService(context, procRoot);
+ service.mBandwidthControlEnabled = bandwidthControlEnabled;
+ return service;
}
public void systemReady() {
@@ -930,13 +939,68 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- final String[] ifaces = listInterfaces();
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), ifaces.length);
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
- for (String iface : ifaces) {
- final long rx = getInterfaceCounter(iface, true);
- final long tx = getInterfaceCounter(iface, false);
- stats.addEntry(iface, UID_ALL, TAG_NONE, rx, tx);
+ final HashSet<String> activeIfaces = Sets.newHashSet();
+ final ArrayList<String> values = Lists.newArrayList();
+
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(mStatsIface));
+
+ // skip first two header lines
+ reader.readLine();
+ reader.readLine();
+
+ // parse remaining lines
+ String line;
+ while ((line = reader.readLine()) != null) {
+ splitLine(line, values);
+
+ try {
+ entry.iface = values.get(0);
+ entry.uid = UID_ALL;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = Long.parseLong(values.get(1));
+ entry.rxPackets = Long.parseLong(values.get(2));
+ entry.txBytes = Long.parseLong(values.get(9));
+ entry.txPackets = Long.parseLong(values.get(10));
+
+ activeIfaces.add(entry.iface);
+ stats.addValues(entry);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
+ }
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "problem parsing stats: " + e);
+ } finally {
+ IoUtils.closeQuietly(reader);
+ }
+
+ if (DBG) Slog.d(TAG, "recorded active stats from " + activeIfaces);
+
+ // splice in stats from any disabled ifaces
+ if (mBandwidthControlEnabled) {
+ final HashSet<String> xtIfaces = Sets.newHashSet(fileListWithoutNull(mStatsXtIface));
+ xtIfaces.removeAll(activeIfaces);
+
+ for (String iface : xtIfaces) {
+ final File ifacePath = new File(mStatsXtIface, iface);
+
+ entry.iface = iface;
+ entry.uid = UID_ALL;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
+ entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
+ entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
+ entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
+
+ stats.addValues(entry);
+ }
+
+ if (DBG) Slog.d(TAG, "recorded stale stats from " + xtIfaces);
}
return stats;
@@ -1063,13 +1127,15 @@
*/
private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+
final ArrayList<String> keys = Lists.newArrayList();
final ArrayList<String> values = Lists.newArrayList();
final HashMap<String, String> parsed = Maps.newHashMap();
BufferedReader reader = null;
try {
- reader = new BufferedReader(new FileReader(mProcStatsNetfilter));
+ reader = new BufferedReader(new FileReader(mStatsXtUid));
// parse first line as header
String line = reader.readLine();
@@ -1081,15 +1147,16 @@
parseLine(keys, values, parsed);
try {
- final String iface = parsed.get(KEY_IFACE);
- final int tag = NetworkManagementSocketTagger.kernelToTag(
+ // TODO: add rxPackets/txPackets once kernel exports
+ entry.iface = parsed.get(KEY_IFACE);
+ entry.tag = NetworkManagementSocketTagger.kernelToTag(
parsed.get(KEY_TAG_HEX));
- final int uid = Integer.parseInt(parsed.get(KEY_UID));
- final long rx = Long.parseLong(parsed.get(KEY_RX));
- final long tx = Long.parseLong(parsed.get(KEY_TX));
+ entry.uid = Integer.parseInt(parsed.get(KEY_UID));
+ entry.rxBytes = Long.parseLong(parsed.get(KEY_RX));
+ entry.txBytes = Long.parseLong(parsed.get(KEY_TX));
- if (limitUid == UID_ALL || limitUid == uid) {
- stats.addEntry(iface, uid, tag, rx, tx);
+ if (limitUid == UID_ALL || limitUid == entry.uid) {
+ stats.addValues(entry);
}
} catch (NumberFormatException e) {
Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
@@ -1114,19 +1181,27 @@
private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
final String[] knownUids;
if (limitUid == UID_ALL) {
- knownUids = mProcStatsUidstat.list();
+ knownUids = fileListWithoutNull(mStatsUid);
} else {
knownUids = new String[] { String.valueOf(limitUid) };
}
final NetworkStats stats = new NetworkStats(
SystemClock.elapsedRealtime(), knownUids.length);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
for (String uid : knownUids) {
final int uidInt = Integer.parseInt(uid);
- final File uidPath = new File(mProcStatsUidstat, uid);
- final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
- final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
- stats.addEntry(IFACE_ALL, uidInt, TAG_NONE, rx, tx);
+ final File uidPath = new File(mStatsUid, uid);
+
+ entry.iface = IFACE_ALL;
+ entry.uid = uidInt;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
+ entry.rxPackets = readSingleLongFromFile(new File(uidPath, "tcp_rcv_pkt"));
+ entry.txBytes = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
+ entry.txPackets = readSingleLongFromFile(new File(uidPath, "tcp_snd_pkt"));
+
+ stats.addValues(entry);
}
return stats;
@@ -1197,7 +1272,7 @@
private static void splitLine(String line, ArrayList<String> outSplit) {
outSplit.clear();
- final StringTokenizer t = new StringTokenizer(line);
+ final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
while (t.hasMoreTokens()) {
outSplit.add(t.nextToken());
}
@@ -1232,6 +1307,15 @@
}
}
+ /**
+ * Wrapper for {@link File#list()} that returns empty array instead of
+ * {@code null}.
+ */
+ private static String[] fileListWithoutNull(File file) {
+ final String[] list = file.list();
+ return list != null ? list : new String[0];
+ }
+
public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 62f0fea..8501163 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -208,6 +208,12 @@
// before we decide it's never going to come up for real.
static final int PROC_START_TIMEOUT = 10*1000;
+ // How long we wait for a launched process to attach to the activity manager
+ // before we decide it's never going to come up for real, when the process was
+ // started with a wrapper for instrumentation (such as Valgrind) because it
+ // could take much longer than usual.
+ static final int PROC_START_TIMEOUT_WITH_WRAPPER = 300*1000;
+
// How long to wait after going idle before forcing apps to GC.
static final int GC_TIMEOUT = 5*1000;
@@ -502,15 +508,6 @@
= new ArrayList<ProcessRecord>();
/**
- * List of records for processes that we have started and are waiting
- * for them to call back. This is really only needed when running in
- * single processes mode, in which case we do not have a unique pid for
- * each process.
- */
- final ArrayList<ProcessRecord> mStartingProcesses
- = new ArrayList<ProcessRecord>();
-
- /**
* List of persistent applications that are in the process
* of being started.
*/
@@ -1959,9 +1956,13 @@
if ("1".equals(SystemProperties.get("debug.assert"))) {
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
- int pid = Process.start("android.app.ActivityThread",
+
+ // Start the process. It will either succeed and return a result containing
+ // the PID of the new process, or else throw a RuntimeException.
+ Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags,
app.info.targetSdkVersion, null);
+
BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
synchronized (bs) {
if (bs.isOnBattery()) {
@@ -1969,12 +1970,12 @@
}
}
- EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
+ EventLog.writeEvent(EventLogTags.AM_PROC_START, startResult.pid, uid,
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
if (app.persistent) {
- Watchdog.getInstance().processStarted(app.processName, pid);
+ Watchdog.getInstance().processStarted(app.processName, startResult.pid);
}
StringBuilder buf = mStringBuilder;
@@ -1988,7 +1989,7 @@
buf.append(hostingNameStr);
}
buf.append(": pid=");
- buf.append(pid);
+ buf.append(startResult.pid);
buf.append(" uid=");
buf.append(uid);
buf.append(" gids={");
@@ -2001,26 +2002,15 @@
}
buf.append("}");
Slog.i(TAG, buf.toString());
- if (pid == 0 || pid == MY_PID) {
- // Processes are being emulated with threads.
- app.pid = MY_PID;
- app.removed = false;
- mStartingProcesses.add(app);
- } else if (pid > 0) {
- app.pid = pid;
- app.removed = false;
- synchronized (mPidsSelfLocked) {
- this.mPidsSelfLocked.put(pid, app);
- Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
- msg.obj = app;
- mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
- }
- } else {
- app.pid = 0;
- RuntimeException e = new RuntimeException(
- "Failure starting process " + app.processName
- + ": returned pid=" + pid);
- Slog.e(TAG, e.getMessage(), e);
+ app.pid = startResult.pid;
+ app.usingWrapper = startResult.usingWrapper;
+ app.removed = false;
+ synchronized (mPidsSelfLocked) {
+ this.mPidsSelfLocked.put(startResult.pid, app);
+ Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
+ msg.obj = app;
+ mHandler.sendMessageDelayed(msg, startResult.usingWrapper
+ ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
} catch (RuntimeException e) {
// XXX do better error recovery.
@@ -3606,9 +3596,6 @@
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
- } else if (mStartingProcesses.size() > 0) {
- app = mStartingProcesses.remove(0);
- app.setPid(pid);
} else {
app = null;
}
@@ -4042,8 +4029,7 @@
synchronized(this) {
int callingUid = Binder.getCallingUid();
try {
- if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
- Process.supportsProcesses()) {
+ if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
int uid = AppGlobals.getPackageManager()
.getPackageUid(packageName);
if (uid != Binder.getCallingUid()) {
@@ -4302,8 +4288,7 @@
}
// Root, system server and our own process get to do everything.
- if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
- !Process.supportsProcesses()) {
+ if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
// If there is a uid that owns whatever is being accessed, it has
@@ -4447,7 +4432,7 @@
private final boolean checkUriPermissionLocked(Uri uri, int uid,
int modeFlags) {
// Root gets to do everything.
- if (uid == 0 || !Process.supportsProcesses()) {
+ if (uid == 0) {
return true;
}
HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
@@ -5528,8 +5513,8 @@
// CONTENT PROVIDERS
// =========================================================
- private final List generateApplicationProvidersLocked(ProcessRecord app) {
- List providers = null;
+ private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
+ List<ProviderInfo> providers = null;
try {
providers = AppGlobals.getPackageManager().
queryContentProviders(app.processName, app.info.uid,
@@ -5967,7 +5952,7 @@
}
public static final void installSystemProviders() {
- List providers;
+ List<ProviderInfo> providers;
synchronized (mSelf) {
ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
providers = mSelf.generateApplicationProvidersLocked(app);
@@ -6585,13 +6570,6 @@
}
public void systemReady(final Runnable goingCallback) {
- // In the simulator, startRunning will never have been called, which
- // normally sets a few crucial variables. Do it here instead.
- if (!Process.supportsProcesses()) {
- mStartRunning = true;
- mTopAction = Intent.ACTION_MAIN;
- }
-
synchronized(this) {
if (mSystemReady) {
if (goingCallback != null) goingCallback.run();
@@ -7955,14 +7933,6 @@
"Starting Norm", "Restarting PERS");
}
- if (mStartingProcesses.size() > 0) {
- if (needSep) pw.println(" ");
- needSep = true;
- pw.println(" Processes that are starting:");
- dumpProcessList(pw, this, mStartingProcesses, " ",
- "Starting Norm", "Starting PERS");
- }
-
if (mRemovedProcesses.size() > 0) {
if (needSep) pw.println(" ");
needSep = true;
@@ -13128,74 +13098,72 @@
int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
- if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
- if (app.curRawAdj != app.setRawAdj) {
- if (app.curRawAdj > FOREGROUND_APP_ADJ
- && app.setRawAdj <= FOREGROUND_APP_ADJ) {
- // If this app is transitioning from foreground to
- // non-foreground, have it do a gc.
- scheduleAppGcLocked(app);
- } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
- && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
- // Likewise do a gc when an app is moving in to the
- // background (such as a service stopping).
- scheduleAppGcLocked(app);
- }
+ if (app.curRawAdj != app.setRawAdj) {
+ if (app.curRawAdj > FOREGROUND_APP_ADJ
+ && app.setRawAdj <= FOREGROUND_APP_ADJ) {
+ // If this app is transitioning from foreground to
+ // non-foreground, have it do a gc.
+ scheduleAppGcLocked(app);
+ } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
+ && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
+ // Likewise do a gc when an app is moving in to the
+ // background (such as a service stopping).
+ scheduleAppGcLocked(app);
+ }
- if (wasKeeping && !app.keeping) {
- // This app is no longer something we want to keep. Note
- // its current wake lock time to later know to kill it if
- // it is not behaving well.
- BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
- app.pid, SystemClock.elapsedRealtime());
+ if (wasKeeping && !app.keeping) {
+ // This app is no longer something we want to keep. Note
+ // its current wake lock time to later know to kill it if
+ // it is not behaving well.
+ BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ synchronized (stats) {
+ app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
+ app.pid, SystemClock.elapsedRealtime());
+ }
+ app.lastCpuTime = app.curCpuTime;
+ }
+
+ app.setRawAdj = app.curRawAdj;
+ }
+ if (adj != app.setAdj) {
+ if (Process.setOomAdj(app.pid, adj)) {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
+ TAG, "Set app " + app.processName +
+ " oom adj to " + adj);
+ app.setAdj = adj;
+ } else {
+ success = false;
+ }
+ }
+ if (app.setSchedGroup != app.curSchedGroup) {
+ app.setSchedGroup = app.curSchedGroup;
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Setting process group of " + app.processName
+ + " to " + app.curSchedGroup);
+ if (app.waitingToKill != null &&
+ app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, app.waitingToKill);
+ Process.killProcessQuiet(app.pid);
+ } else {
+ if (true) {
+ long oldId = Binder.clearCallingIdentity();
+ try {
+ Process.setProcessGroup(app.pid, app.curSchedGroup);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed setting process group of " + app.pid
+ + " to " + app.curSchedGroup);
+ e.printStackTrace();
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
- app.lastCpuTime = app.curCpuTime;
}
-
- app.setRawAdj = app.curRawAdj;
- }
- if (adj != app.setAdj) {
- if (Process.setOomAdj(app.pid, adj)) {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
- TAG, "Set app " + app.processName +
- " oom adj to " + adj);
- app.setAdj = adj;
- } else {
- success = false;
- }
- }
- if (app.setSchedGroup != app.curSchedGroup) {
- app.setSchedGroup = app.curSchedGroup;
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
- "Setting process group of " + app.processName
- + " to " + app.curSchedGroup);
- if (app.waitingToKill != null &&
- app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, app.waitingToKill);
- Process.killProcessQuiet(app.pid);
- } else {
- if (true) {
- long oldId = Binder.clearCallingIdentity();
+ if (false) {
+ if (app.thread != null) {
try {
- Process.setProcessGroup(app.pid, app.curSchedGroup);
- } catch (Exception e) {
- Slog.w(TAG, "Failed setting process group of " + app.pid
- + " to " + app.curSchedGroup);
- e.printStackTrace();
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
- if (false) {
- if (app.thread != null) {
- try {
- app.thread.setSchedulingGroup(app.curSchedGroup);
- } catch (RemoteException e) {
- }
+ app.thread.setSchedulingGroup(app.curSchedGroup);
+ } catch (RemoteException e) {
}
}
}
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 090e26b..73ffafb 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -658,12 +658,12 @@
public long getKeyDispatchingTimeout() {
synchronized(service) {
ActivityRecord r = getWaitingHistoryRecordLocked();
- if (r == null || r.app == null
- || r.app.instrumentationClass == null) {
- return ActivityManagerService.KEY_DISPATCHING_TIMEOUT;
+ if (r != null && r.app != null
+ && (r.app.instrumentationClass != null || r.app.usingWrapper)) {
+ return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
}
-
- return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
+
+ return ActivityManagerService.KEY_DISPATCHING_TIMEOUT;
}
}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 3968f66..da83e7d 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -78,6 +78,7 @@
IInstrumentationWatcher instrumentationWatcher; // who is waiting
Bundle instrumentationArguments;// as given to us
ComponentName instrumentationResultClass;// copy of instrumentationClass
+ boolean usingWrapper; // Set to true when process was launched with a wrapper attached
BroadcastRecord curReceiver;// receiver currently running in the app
long lastWakeTime; // How long proc held wake lock at last check
long lastCpuTime; // How long proc has run CPU at last check
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 6e8f248..12c8ccf 100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -63,7 +63,7 @@
private static final String TAG = "UsageStats";
// Current on-disk Parcel version
- private static final int VERSION = 1005;
+ private static final int VERSION = 1006;
private static final int CHECKIN_VERSION = 4;
@@ -145,6 +145,8 @@
final HashMap<String, TimeStats> mLaunchTimes
= new HashMap<String, TimeStats>();
int mLaunchCount;
+ final HashMap<String, Long> mLastResumeTimes
+ = new HashMap<String, Long>();
long mUsageTime;
long mPausedTime;
long mResumedTime;
@@ -160,20 +162,28 @@
if (localLOGV) Slog.v(TAG, "Launch count: " + mLaunchCount
+ ", Usage time:" + mUsageTime);
- final int N = in.readInt();
- if (localLOGV) Slog.v(TAG, "Reading comps: " + N);
- for (int i=0; i<N; i++) {
+ final int numTimeStats = in.readInt();
+ if (localLOGV) Slog.v(TAG, "Reading comps: " + numTimeStats);
+ for (int i=0; i<numTimeStats; i++) {
String comp = in.readString();
if (localLOGV) Slog.v(TAG, "Component: " + comp);
TimeStats times = new TimeStats(in);
mLaunchTimes.put(comp, times);
}
+ final int numResumeTimes = in.readInt();
+ if (localLOGV) Slog.v(TAG, "Reading last resume times: " + numResumeTimes);
+ for (int i=0; i<numResumeTimes; i++) {
+ String comp = in.readString();
+ if (localLOGV) Slog.v(TAG, "Component: " + comp);
+ mLastResumeTimes.put(comp, in.readLong());
+ }
}
-
- void updateResume(boolean launched) {
+
+ void updateResume(String comp, boolean launched) {
if (launched) {
mLaunchCount ++;
}
+ mLastResumeTimes.put(comp, System.currentTimeMillis());
mResumedTime = SystemClock.elapsedRealtime();
}
@@ -203,20 +213,29 @@
void writeToParcel(Parcel out) {
out.writeInt(mLaunchCount);
out.writeLong(mUsageTime);
- final int N = mLaunchTimes.size();
- out.writeInt(N);
- if (N > 0) {
+ final int numTimeStats = mLaunchTimes.size();
+ out.writeInt(numTimeStats);
+ if (numTimeStats > 0) {
for (Map.Entry<String, TimeStats> ent : mLaunchTimes.entrySet()) {
out.writeString(ent.getKey());
TimeStats times = ent.getValue();
times.writeToParcel(out);
}
}
+ final int numResumeTimes = mLastResumeTimes.size();
+ out.writeInt(numResumeTimes);
+ if (numResumeTimes > 0) {
+ for (Map.Entry<String, Long> ent : mLastResumeTimes.entrySet()) {
+ out.writeString(ent.getKey());
+ out.writeLong(ent.getValue());
+ }
+ }
}
void clear() {
mLaunchTimes.clear();
mLaunchCount = 0;
+ mLastResumeTimes.clear();
mUsageTime = 0;
}
}
@@ -546,7 +565,7 @@
pus = new PkgUsageStatsExtended();
mStats.put(pkgName, pus);
}
- pus.updateResume(!samePackage);
+ pus.updateResume(mLastResumedComp, !samePackage);
if (!sameComp) {
pus.addLaunchCount(mLastResumedComp);
}
@@ -624,7 +643,8 @@
if (pus == null) {
return null;
}
- return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime);
+ return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime,
+ pus.mLastResumeTimes);
}
}
@@ -641,7 +661,8 @@
int i = 0;
for (String key: keys) {
PkgUsageStatsExtended pus = mStats.get(key);
- retArr[i] = new PkgUsageStats(key, pus.mLaunchCount, pus.mUsageTime);
+ retArr[i] = new PkgUsageStats(key, pus.mLaunchCount, pus.mUsageTime,
+ pus.mLastResumeTimes);
i++;
}
return retArr;
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 6bb7949..d7d4b03 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -221,8 +221,6 @@
}
public void interfaceLinkStateChanged(String iface, boolean up) {
- if (DEBUG) Log.d(TAG, "interfaceLinkStateChanged " + iface + ", " + up);
- interfaceStatusChanged(iface, up);
}
private boolean isUsb(String iface) {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index ea5d26b..d6a15e6 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -778,16 +778,7 @@
mSeparateProcesses = null;
}
- Installer installer = new Installer();
- // Little hacky thing to check if installd is here, to determine
- // whether we are running on the simulator and thus need to take
- // care of building the /data file structure ourself.
- // (apparently the sim now has a working installer)
- if (installer.ping() && Process.supportsProcesses()) {
- mInstaller = installer;
- } else {
- mInstaller = null;
- }
+ mInstaller = new Installer();
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
@@ -806,17 +797,6 @@
mUserManager = new UserManager(mInstaller, mUserAppDataDir);
- if (mInstaller == null) {
- // Make sure these dirs exist, when we are running in
- // the simulator.
- // Make a wide-open directory for random misc stuff.
- File miscDir = new File(dataDir, "misc");
- miscDir.mkdirs();
- mAppDataDir.mkdirs();
- mUserAppDataDir.mkdirs();
- mDrmAppPrivateInstallDir.mkdirs();
- }
-
readPermissions();
mRestoredSettings = mSettings.readLPw();
@@ -838,104 +818,102 @@
mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
mDalvikCacheDir = new File(dataDir, "dalvik-cache");
- if (mInstaller != null) {
- boolean didDexOpt = false;
+ boolean didDexOpt = false;
- /**
- * Out of paranoia, ensure that everything in the boot class
- * path has been dexed.
- */
- String bootClassPath = System.getProperty("java.boot.class.path");
- if (bootClassPath != null) {
- String[] paths = splitString(bootClassPath, ':');
- for (int i=0; i<paths.length; i++) {
- try {
- if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
- libFiles.add(paths[i]);
- mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
- didDexOpt = true;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Boot class path not found: " + paths[i]);
- } catch (IOException e) {
- Slog.w(TAG, "Exception reading boot class path: " + paths[i], e);
+ /**
+ * Out of paranoia, ensure that everything in the boot class
+ * path has been dexed.
+ */
+ String bootClassPath = System.getProperty("java.boot.class.path");
+ if (bootClassPath != null) {
+ String[] paths = splitString(bootClassPath, ':');
+ for (int i=0; i<paths.length; i++) {
+ try {
+ if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
+ libFiles.add(paths[i]);
+ mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
+ didDexOpt = true;
}
- }
- } else {
- Slog.w(TAG, "No BOOTCLASSPATH found!");
- }
-
- /**
- * Also ensure all external libraries have had dexopt run on them.
- */
- if (mSharedLibraries.size() > 0) {
- Iterator<String> libs = mSharedLibraries.values().iterator();
- while (libs.hasNext()) {
- String lib = libs.next();
- try {
- if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
- libFiles.add(lib);
- mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
- didDexOpt = true;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Library not found: " + lib);
- } catch (IOException e) {
- Slog.w(TAG, "Exception reading library: " + lib, e);
- }
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Boot class path not found: " + paths[i]);
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception reading boot class path: " + paths[i], e);
}
}
+ } else {
+ Slog.w(TAG, "No BOOTCLASSPATH found!");
+ }
- // Gross hack for now: we know this file doesn't contain any
- // code, so don't dexopt it to avoid the resulting log spew.
- libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
-
- /**
- * And there are a number of commands implemented in Java, which
- * we currently need to do the dexopt on so that they can be
- * run from a non-root shell.
- */
- String[] frameworkFiles = mFrameworkDir.list();
- if (frameworkFiles != null) {
- for (int i=0; i<frameworkFiles.length; i++) {
- File libPath = new File(mFrameworkDir, frameworkFiles[i]);
- String path = libPath.getPath();
- // Skip the file if we alrady did it.
- if (libFiles.contains(path)) {
- continue;
+ /**
+ * Also ensure all external libraries have had dexopt run on them.
+ */
+ if (mSharedLibraries.size() > 0) {
+ Iterator<String> libs = mSharedLibraries.values().iterator();
+ while (libs.hasNext()) {
+ String lib = libs.next();
+ try {
+ if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
+ libFiles.add(lib);
+ mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
+ didDexOpt = true;
}
- // Skip the file if it is not a type we want to dexopt.
- if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
- continue;
- }
- try {
- if (dalvik.system.DexFile.isDexOptNeeded(path)) {
- mInstaller.dexopt(path, Process.SYSTEM_UID, true);
- didDexOpt = true;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Jar not found: " + path);
- } catch (IOException e) {
- Slog.w(TAG, "Exception reading jar: " + path, e);
- }
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Library not found: " + lib);
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception reading library: " + lib, e);
}
}
+ }
- if (didDexOpt) {
- // If we had to do a dexopt of one of the previous
- // things, then something on the system has changed.
- // Consider this significant, and wipe away all other
- // existing dexopt files to ensure we don't leave any
- // dangling around.
- String[] files = mDalvikCacheDir.list();
- if (files != null) {
- for (int i=0; i<files.length; i++) {
- String fn = files[i];
- if (fn.startsWith("data@app@")
- || fn.startsWith("data@app-private@")) {
- Slog.i(TAG, "Pruning dalvik file: " + fn);
- (new File(mDalvikCacheDir, fn)).delete();
- }
+ // Gross hack for now: we know this file doesn't contain any
+ // code, so don't dexopt it to avoid the resulting log spew.
+ libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
+
+ /**
+ * And there are a number of commands implemented in Java, which
+ * we currently need to do the dexopt on so that they can be
+ * run from a non-root shell.
+ */
+ String[] frameworkFiles = mFrameworkDir.list();
+ if (frameworkFiles != null) {
+ for (int i=0; i<frameworkFiles.length; i++) {
+ File libPath = new File(mFrameworkDir, frameworkFiles[i]);
+ String path = libPath.getPath();
+ // Skip the file if we alrady did it.
+ if (libFiles.contains(path)) {
+ continue;
+ }
+ // Skip the file if it is not a type we want to dexopt.
+ if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
+ continue;
+ }
+ try {
+ if (dalvik.system.DexFile.isDexOptNeeded(path)) {
+ mInstaller.dexopt(path, Process.SYSTEM_UID, true);
+ didDexOpt = true;
+ }
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Jar not found: " + path);
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception reading jar: " + path, e);
+ }
+ }
+ }
+
+ if (didDexOpt) {
+ // If we had to do a dexopt of one of the previous
+ // things, then something on the system has changed.
+ // Consider this significant, and wipe away all other
+ // existing dexopt files to ensure we don't leave any
+ // dangling around.
+ String[] files = mDalvikCacheDir.list();
+ if (files != null) {
+ for (int i=0; i<files.length; i++) {
+ String fn = files[i];
+ if (fn.startsWith("data@app@")
+ || fn.startsWith("data@app-private@")) {
+ Slog.i(TAG, "Pruning dalvik file: " + fn);
+ (new File(mDalvikCacheDir, fn)).delete();
}
}
}
@@ -965,11 +943,9 @@
scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
- if (mInstaller != null) {
- if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
- mInstaller.moveFiles();
- }
-
+ if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
+ mInstaller.moveFiles();
+
// Prune any system packages that no longer exist.
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
@@ -981,19 +957,12 @@
String msg = "System package " + ps.name
+ " no longer exists; wiping its data";
reportSettingsProblem(Log.WARN, msg);
- if (mInstaller != null) {
- mInstaller.remove(ps.name, 0);
- mUserManager.removePackageForAllUsers(ps.name);
- }
+ mInstaller.remove(ps.name, 0);
+ mUserManager.removePackageForAllUsers(ps.name);
}
}
mAppInstallDir = new File(dataDir, "app");
- if (mInstaller == null) {
- // Make sure these dirs exist, when we are running in
- // the simulator.
- mAppInstallDir.mkdirs(); // scanDirLI() assumes this dir exists
- }
//look for any incomplete package installations
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
@@ -1067,19 +1036,12 @@
void cleanupInstallFailedPackage(PackageSetting ps) {
Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
- if (mInstaller != null) {
- int retCode = mInstaller.remove(ps.name, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data directory for package: "
- + ps.name + ", retcode=" + retCode);
- } else {
- mUserManager.removePackageForAllUsers(ps.name);
- }
+ int retCode = mInstaller.remove(ps.name, 0);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove app data directory for package: "
+ + ps.name + ", retcode=" + retCode);
} else {
- //for emulator
- PackageParser.Package pkg = mPackages.get(ps.name);
- File dataDir = new File(pkg.applicationInfo.dataDir);
- dataDir.delete();
+ mUserManager.removePackageForAllUsers(ps.name);
}
if (ps.codePath != null) {
if (!ps.codePath.delete()) {
@@ -1562,12 +1524,10 @@
public void run() {
mHandler.removeCallbacks(this);
int retCode = -1;
- if (mInstaller != null) {
- retCode = mInstaller.freeCache(freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
- }
- } //end if mInstaller
+ retCode = mInstaller.freeCache(freeStorageSize);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't clear application caches");
+ }
if (observer != null) {
try {
observer.onRemoveCompleted(null, (retCode >= 0));
@@ -1587,11 +1547,9 @@
public void run() {
mHandler.removeCallbacks(this);
int retCode = -1;
- if (mInstaller != null) {
- retCode = mInstaller.freeCache(freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
- }
+ retCode = mInstaller.freeCache(freeStorageSize);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't clear application caches");
}
if(pi != null) {
try {
@@ -2850,7 +2808,7 @@
private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) {
boolean performed = false;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0 && mInstaller != null) {
+ if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
String path = pkg.mScanPath;
int ret = 0;
try {
@@ -3235,42 +3193,39 @@
mOutPermissions[1] = 0;
FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
- // If we have mismatched owners for the data path, we have a
- // problem (unless we're running in the simulator.)
- if (mOutPermissions[1] != pkg.applicationInfo.uid && Process.supportsProcesses()) {
+ // If we have mismatched owners for the data path, we have a problem.
+ if (mOutPermissions[1] != pkg.applicationInfo.uid) {
boolean recovered = false;
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
// If this is a system app, we can at least delete its
// current data so the application will still work.
- if (mInstaller != null) {
- int ret = mInstaller.remove(pkgName, 0);
- if (ret >= 0) {
- // TODO: Kill the processes first
- // Remove the data directories for all users
- mUserManager.removePackageForAllUsers(pkgName);
- // Old data gone!
- String msg = "System package " + pkg.packageName
- + " has changed from uid: "
- + mOutPermissions[1] + " to "
- + pkg.applicationInfo.uid + "; old data erased";
- reportSettingsProblem(Log.WARN, msg);
- recovered = true;
+ int ret = mInstaller.remove(pkgName, 0);
+ if (ret >= 0) {
+ // TODO: Kill the processes first
+ // Remove the data directories for all users
+ mUserManager.removePackageForAllUsers(pkgName);
+ // Old data gone!
+ String msg = "System package " + pkg.packageName
+ + " has changed from uid: "
+ + mOutPermissions[1] + " to "
+ + pkg.applicationInfo.uid + "; old data erased";
+ reportSettingsProblem(Log.WARN, msg);
+ recovered = true;
- // And now re-install the app.
- ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
- if (ret == -1) {
- // Ack should not happen!
- msg = "System package " + pkg.packageName
- + " could not have data directory re-created after delete.";
- reportSettingsProblem(Log.WARN, msg);
- mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- return null;
- }
- // Create data directories for all users
- mUserManager.installPackageForAllUsers(pkgName,
- pkg.applicationInfo.uid);
+ // And now re-install the app.
+ ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
+ pkg.applicationInfo.uid);
+ if (ret == -1) {
+ // Ack should not happen!
+ msg = "System package " + pkg.packageName
+ + " could not have data directory re-created after delete.";
+ reportSettingsProblem(Log.WARN, msg);
+ mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return null;
}
+ // Create data directories for all users
+ mUserManager.installPackageForAllUsers(pkgName,
+ pkg.applicationInfo.uid);
}
if (!recovered) {
mHasSystemUidErrors = true;
@@ -3303,25 +3258,16 @@
Log.v(TAG, "Want this data dir: " + dataPath);
}
//invoke installer to do the actual installation
- if (mInstaller != null) {
- int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
- if (ret < 0) {
- // Error from installer
- mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- return null;
- }
- // Create data directories for all users
- mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
- } else {
- dataPath.mkdirs();
- if (dataPath.exists()) {
- FileUtils.setPermissions(
- dataPath.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
- pkg.applicationInfo.uid, pkg.applicationInfo.uid);
- }
+ int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
+ pkg.applicationInfo.uid);
+ if (ret < 0) {
+ // Error from installer
+ mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return null;
}
+ // Create data directories for all users
+ mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
+
if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
@@ -3352,65 +3298,62 @@
pkgSetting.uidError = uidError;
}
- // If we're running in the simulator, we don't need to unpack anything.
- if (mInstaller != null) {
- String path = scanFile.getPath();
- /* Note: We don't want to unpack the native binaries for
- * system applications, unless they have been updated
- * (the binaries are already under /system/lib).
- * Also, don't unpack libs for apps on the external card
- * since they should have their libraries in the ASEC
- * container already.
- *
- * In other words, we're going to unpack the binaries
- * only for non-system apps and system app upgrades.
- */
- if (pkg.applicationInfo.nativeLibraryDir != null) {
- try {
- final File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
- final String dataPathString = dataPath.getCanonicalFile().getPath();
+ String path = scanFile.getPath();
+ /* Note: We don't want to unpack the native binaries for
+ * system applications, unless they have been updated
+ * (the binaries are already under /system/lib).
+ * Also, don't unpack libs for apps on the external card
+ * since they should have their libraries in the ASEC
+ * container already.
+ *
+ * In other words, we're going to unpack the binaries
+ * only for non-system apps and system app upgrades.
+ */
+ if (pkg.applicationInfo.nativeLibraryDir != null) {
+ try {
+ final File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
+ final String dataPathString = dataPath.getCanonicalFile().getPath();
- if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
- /*
- * Upgrading from a previous version of the OS sometimes
- * leaves native libraries in the /data/data/<app>/lib
- * directory for system apps even when they shouldn't be.
- * Recent changes in the JNI library search path
- * necessitates we remove those to match previous behavior.
- */
- if (NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryDir)) {
- Log.i(TAG, "removed obsolete native libraries for system package "
- + path);
- }
- } else if (nativeLibraryDir.getCanonicalFile().getParent()
- .equals(dataPathString)) {
- /*
- * If this is an internal application or our
- * nativeLibraryPath points to our data directory, unpack
- * the libraries. The native library path pointing to the
- * data directory for an application in an ASEC container
- * can happen for older apps that existed before an OTA to
- * Gingerbread.
- */
- Slog.i(TAG, "Unpacking native libraries for " + path);
- mInstaller.unlinkNativeLibraryDirectory(dataPathString);
- NativeLibraryHelper.copyNativeBinariesLI(scanFile, nativeLibraryDir);
- } else {
- Slog.i(TAG, "Linking native library dir for " + path);
- mInstaller.linkNativeLibraryDirectory(dataPathString,
- pkg.applicationInfo.nativeLibraryDir);
+ if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
+ /*
+ * Upgrading from a previous version of the OS sometimes
+ * leaves native libraries in the /data/data/<app>/lib
+ * directory for system apps even when they shouldn't be.
+ * Recent changes in the JNI library search path
+ * necessitates we remove those to match previous behavior.
+ */
+ if (NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryDir)) {
+ Log.i(TAG, "removed obsolete native libraries for system package "
+ + path);
}
- } catch (IOException ioe) {
- Log.e(TAG, "Unable to get canonical file " + ioe.toString());
+ } else if (nativeLibraryDir.getCanonicalFile().getParent()
+ .equals(dataPathString)) {
+ /*
+ * If this is an internal application or our
+ * nativeLibraryPath points to our data directory, unpack
+ * the libraries. The native library path pointing to the
+ * data directory for an application in an ASEC container
+ * can happen for older apps that existed before an OTA to
+ * Gingerbread.
+ */
+ Slog.i(TAG, "Unpacking native libraries for " + path);
+ mInstaller.unlinkNativeLibraryDirectory(dataPathString);
+ NativeLibraryHelper.copyNativeBinariesLI(scanFile, nativeLibraryDir);
+ } else {
+ Slog.i(TAG, "Linking native library dir for " + path);
+ mInstaller.linkNativeLibraryDirectory(dataPathString,
+ pkg.applicationInfo.nativeLibraryDir);
}
+ } catch (IOException ioe) {
+ Log.e(TAG, "Unable to get canonical file " + ioe.toString());
}
- pkg.mScanPath = path;
+ }
+ pkg.mScanPath = path;
- if ((scanMode&SCAN_NO_DEX) == 0) {
- if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
- mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
- return null;
- }
+ if ((scanMode&SCAN_NO_DEX) == 0) {
+ if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
+ mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
+ return null;
}
}
@@ -5434,7 +5377,7 @@
void cleanUpResourcesLI() {
String sourceDir = getCodePath();
- if (cleanUp() && mInstaller != null) {
+ if (cleanUp()) {
int retCode = mInstaller.rmdex(sourceDir);
if (retCode < 0) {
Slog.w(TAG, "Couldn't remove dex file for package: "
@@ -5662,14 +5605,12 @@
void cleanUpResourcesLI() {
String sourceFile = getCodePath();
// Remove dex file
- if (mInstaller != null) {
- int retCode = mInstaller.rmdex(sourceFile);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location "
- + sourceFile.toString() + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- }
+ int retCode = mInstaller.rmdex(sourceFile);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove dex file for package: "
+ + " at location "
+ + sourceFile.toString() + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
}
cleanUp();
}
@@ -6077,9 +6018,7 @@
}
if((res.returnCode = setPermissionsLI(newPackage))
!= PackageManager.INSTALL_SUCCEEDED) {
- if (mInstaller != null) {
- mInstaller.rmdex(newPackage.mScanPath);
- }
+ mInstaller.rmdex(newPackage.mScanPath);
return;
} else {
Log.d(TAG, "New package installed in " + newPackage.mPath);
@@ -6207,15 +6146,8 @@
} finally {
//TODO clean up the extracted public files
}
- if (mInstaller != null) {
- retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
- newPackage.applicationInfo.uid);
- } else {
- final int filePermissions =
- FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP;
- retCode = FileUtils.setPermissions(newPackage.mPath, filePermissions, -1,
- newPackage.applicationInfo.uid);
- }
+ retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
+ newPackage.applicationInfo.uid);
} else {
// The permissions on the resource file was set when it was copied for
// non forward locked apps and apps on sdcard
@@ -6478,25 +6410,14 @@
deletedPs = mSettings.mPackages.get(packageName);
}
if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
- if (mInstaller != null) {
- int retCode = mInstaller.remove(packageName, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data or cache directory for package: "
- + packageName + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- } else {
- // TODO: Kill the processes first
- mUserManager.removePackageForAllUsers(packageName);
- }
+ int retCode = mInstaller.remove(packageName, 0);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove app data or cache directory for package: "
+ + packageName + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
} else {
- // for simulator
- File dataDir;
- // reader
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(packageName);
- dataDir = new File(pkg.applicationInfo.dataDir);
- }
- dataDir.delete();
+ // TODO: Kill the processes first
+ mUserManager.removePackageForAllUsers(packageName);
}
schedulePackageCleaning(packageName);
}
@@ -6745,13 +6666,11 @@
return false;
}
}
- if (mInstaller != null) {
- int retCode = mInstaller.clearUserData(packageName, 0); // TODO - correct userId
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package: "
- + packageName);
- return false;
- }
+ int retCode = mInstaller.clearUserData(packageName, 0); // TODO - correct userId
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove cache files for package: "
+ + packageName);
+ return false;
}
return true;
}
@@ -6797,13 +6716,11 @@
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- if (mInstaller != null) {
- int retCode = mInstaller.deleteCacheFiles(packageName);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package: "
- + packageName);
- return false;
- }
+ int retCode = mInstaller.deleteCacheFiles(packageName);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove cache files for package: "
+ + packageName);
+ return false;
}
return true;
}
@@ -6867,14 +6784,10 @@
publicSrcDir = applicationInfo.publicSourceDir;
}
}
- if (mInstaller != null) {
- int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir,
- asecPath, pStats);
- if (res < 0) {
- return false;
- } else {
- return true;
- }
+ int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir,
+ asecPath, pStats);
+ if (res < 0) {
+ return false;
}
return true;
}
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 1ab570a..86b3d36 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -251,19 +251,18 @@
public UsbHandler() {
try {
+ // persist.sys.usb.config should never be unset. But if it is, set it to "adb"
+ // so we have a chance of debugging what happened.
+ mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
// sanity check the sys.usb.config system property
// this may be necessary if we crashed while switching USB configurations
String config = SystemProperties.get("sys.usb.config", "none");
- if (config.equals("none")) {
- String persistConfig = SystemProperties.get("persist.sys.usb.config", "none");
- Slog.w(TAG, "resetting config to persistent property: " + persistConfig);
- SystemProperties.set("sys.usb.config", persistConfig);
+ if (!config.equals(mDefaultFunctions)) {
+ Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions);
+ SystemProperties.set("sys.usb.config", mDefaultFunctions);
}
- // Read initial USB state
- mCurrentFunctions = FileUtils.readTextFile(
- new File(FUNCTIONS_PATH), 0, null).trim();
- mDefaultFunctions = mCurrentFunctions;
+ mCurrentFunctions = mDefaultFunctions;
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
@@ -621,6 +620,16 @@
pw.println(" mConnected: " + mConnected);
pw.println(" mConfigured: " + mConfigured);
pw.println(" mCurrentAccessory: " + mCurrentAccessory);
+ try {
+ pw.println(" Kernel state: "
+ + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
+ pw.println(" Kernel function list: "
+ + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
+ pw.println(" Mass storage backing file: "
+ + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim());
+ } catch (IOException e) {
+ pw.println("IOException: " + e);
+ }
}
}
diff --git a/services/tests/servicestests/res/raw/net_dev_typical b/services/tests/servicestests/res/raw/net_dev_typical
new file mode 100644
index 0000000..290bf03
--- /dev/null
+++ b/services/tests/servicestests/res/raw/net_dev_typical
@@ -0,0 +1,8 @@
+Inter-| Receive | Transmit
+ face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
+ lo: 8308 116 0 0 0 0 0 0 8308 116 0 0 0 0 0 0
+rmnet0: 1507570 2205 0 0 0 0 0 0 489339 2237 0 0 0 0 0 0
+ ifb0: 52454 151 0 151 0 0 0 0 0 0 0 0 0 0 0 0
+ ifb1: 52454 151 0 151 0 0 0 0 0 0 0 0 0 0 0 0
+ sit0: 0 0 0 0 0 0 0 0 0 0 148 0 0 0 0 0
+ip6tnl0: 0 0 0 0 0 0 0 0 0 0 151 151 0 0 0 0
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
index ac7cb5a..56ef995a 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
import static com.android.server.NetworkManagementSocketTagger.tagToKernel;
@@ -25,9 +27,11 @@
import android.test.suitebuilder.annotation.LargeTest;
import com.android.frameworks.servicestests.R;
+import com.google.common.io.Files;
import java.io.File;
import java.io.FileOutputStream;
+import java.io.FileWriter;
import java.io.InputStream;
import java.io.OutputStream;
@@ -46,14 +50,23 @@
public void setUp() throws Exception {
super.setUp();
- mTestProc = getContext().getFilesDir();
- mService = NetworkManagementService.createForTest(mContext, mTestProc);
+ final File canonicalFilesDir = getContext().getFilesDir().getCanonicalFile();
+ mTestProc = new File(canonicalFilesDir, "proc");
+ if (mTestProc.exists()) {
+ Files.deleteRecursively(mTestProc);
+ }
+
+ mService = NetworkManagementService.createForTest(mContext, mTestProc, true);
}
@Override
public void tearDown() throws Exception {
mService = null;
+ if (mTestProc.exists()) {
+ Files.deleteRecursively(mTestProc);
+ }
+
super.tearDown();
}
@@ -61,7 +74,7 @@
stageFile(R.raw.xt_qtaguid_typical, new File(mTestProc, "net/xt_qtaguid/stats"));
final NetworkStats stats = mService.getNetworkStatsDetail();
- assertEquals(31, stats.size);
+ assertEquals(31, stats.size());
assertStatsEntry(stats, "wlan0", 0, 0, 14615L, 4270L);
assertStatsEntry(stats, "wlan0", 10004, 0, 333821L, 53558L);
assertStatsEntry(stats, "wlan0", 10004, 1947740890, 18725L, 1066L);
@@ -73,11 +86,37 @@
stageFile(R.raw.xt_qtaguid_extended, new File(mTestProc, "net/xt_qtaguid/stats"));
final NetworkStats stats = mService.getNetworkStatsDetail();
- assertEquals(2, stats.size);
+ assertEquals(2, stats.size());
assertStatsEntry(stats, "test0", 1000, 0, 1024L, 2048L);
assertStatsEntry(stats, "test0", 1000, 0xF00D, 512L, 512L);
}
+ public void testNetworkStatsSummary() throws Exception {
+ stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
+
+ final NetworkStats stats = mService.getNetworkStatsSummary();
+ assertEquals(6, stats.size());
+ assertStatsEntry(stats, "lo", UID_ALL, TAG_NONE, 8308L, 8308L);
+ assertStatsEntry(stats, "rmnet0", UID_ALL, TAG_NONE, 1507570L, 489339L);
+ assertStatsEntry(stats, "ifb0", UID_ALL, TAG_NONE, 52454L, 0L);
+ assertStatsEntry(stats, "ifb1", UID_ALL, TAG_NONE, 52454L, 0L);
+ assertStatsEntry(stats, "sit0", UID_ALL, TAG_NONE, 0L, 0L);
+ assertStatsEntry(stats, "ip6tnl0", UID_ALL, TAG_NONE, 0L, 0L);
+ }
+
+ public void testNetworkStatsSummaryDown() throws Exception {
+ stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
+ stageLong(1024L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_bytes"));
+ stageLong(128L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_packets"));
+ stageLong(2048L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_bytes"));
+ stageLong(256L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_packets"));
+
+ final NetworkStats stats = mService.getNetworkStatsSummary();
+ assertEquals(7, stats.size());
+ assertStatsEntry(stats, "rmnet0", UID_ALL, TAG_NONE, 1507570L, 489339L);
+ assertStatsEntry(stats, "wlan0", UID_ALL, TAG_NONE, 1024L, 2048L);
+ }
+
public void testKernelTags() throws Exception {
assertEquals("0", tagToKernel(0x0));
assertEquals("214748364800", tagToKernel(0x32));
@@ -90,7 +129,6 @@
assertEquals(2147483647, kernelToTag("0x7fffffff00000000"));
assertEquals(0, kernelToTag("0x0000000000000000"));
assertEquals(2147483136, kernelToTag("0x7FFFFE0000000000"));
-
}
/**
@@ -111,11 +149,23 @@
}
}
+ private void stageLong(long value, File file) throws Exception {
+ new File(file.getParent()).mkdirs();
+ FileWriter out = null;
+ try {
+ out = new FileWriter(file);
+ out.write(Long.toString(value));
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+
private static void assertStatsEntry(
- NetworkStats stats, String iface, int uid, int tag, long rx, long tx) {
+ NetworkStats stats, String iface, int uid, int tag, long rxBytes, long txBytes) {
final int i = stats.findIndex(iface, uid, tag);
- assertEquals(rx, stats.rx[i]);
- assertEquals(tx, stats.tx[i]);
+ final NetworkStats.Entry entry = stats.getValues(i, null);
+ assertEquals(rxBytes, entry.rxBytes);
+ assertEquals(txBytes, entry.txBytes);
}
}
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back_default.png
new file mode 100644
index 0000000..ac5a97b
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home_default.png
new file mode 100644
index 0000000..a90dc9b
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent_default.png
new file mode 100644
index 0000000..cb3c433
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
index 4bcd2be..5ab09f0 100644
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
index cfeba3e..62ca427 100644
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
index 1d97e05..ff698fb 100644
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back_default.png
new file mode 100644
index 0000000..4cb305d
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home_default.png
new file mode 100644
index 0000000..31d35c8
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent_default.png
new file mode 100644
index 0000000..f0cc341d
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/src/android/view/Display_Delegate.java b/tools/layoutlib/bridge/src/android/view/Display_Delegate.java
new file mode 100644
index 0000000..83f9cc2
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/Display_Delegate.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import com.android.layoutlib.bridge.android.BridgeWindowManager;
+import com.android.layoutlib.bridge.impl.RenderAction;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.os.RemoteException;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link Display}
+ *
+ * Through the layoutlib_create tool, the original methods of Display have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class Display_Delegate {
+
+ // ---- Overridden methods ----
+
+ @LayoutlibDelegate
+ public static IWindowManager getWindowManager() {
+ return RenderAction.getCurrentContext().getIWindowManager();
+ }
+
+ // ---- Native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int getDisplayCount() {
+ return 1;
+ }
+
+ @LayoutlibDelegate
+ /** @hide Returns the actual screen size, not including any decor. */
+ /*package*/ static int getRealWidth(Display theDisplay) {
+ // always dynamically query for the current window manager
+ return RenderAction.getCurrentContext().getIWindowManager().getMetrics().widthPixels;
+ }
+
+ @LayoutlibDelegate
+ /** @hide Returns the actual screen size, not including any decor. */
+ /*package*/ static int getRealHeight(Display theDisplay) {
+ // always dynamically query for the current window manager
+ return RenderAction.getCurrentContext().getIWindowManager().getMetrics().heightPixels;
+ }
+
+ @LayoutlibDelegate
+ /** @hide special for when we are faking the screen size. */
+ /*package*/ static int getRawWidth(Display theDisplay) {
+ // same as real since we're not faking compatibility mode.
+ return getRealWidth(theDisplay);
+ }
+
+ @LayoutlibDelegate
+ /** @hide special for when we are faking the screen size. */
+ /*package*/ static int getRawHeight(Display theDisplay) {
+ // same as real since we're not faking compatibility mode.
+ return getRealHeight(theDisplay);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getOrientation(Display theDisplay) {
+ try {
+ // always dynamically query for the current window manager
+ return getWindowManager().getRotation();
+ } catch (RemoteException e) {
+ // this will never been thrown since this is not a true RPC.
+ }
+
+ return Surface.ROTATION_0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeClassInit() {
+ // not needed for now.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void init(Display theDisplay, int display) {
+ // always dynamically query for the current window manager
+ BridgeWindowManager wm = RenderAction.getCurrentContext().getIWindowManager();
+ theDisplay.mDensity = wm.getMetrics().density;
+ theDisplay.mDpiX = wm.getMetrics().xdpi;
+ theDisplay.mDpiY = wm.getMetrics().ydpi;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 47fa68e..69e0de9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -64,6 +64,7 @@
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.LayoutInflater;
+import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
@@ -91,7 +92,11 @@
private final Object mProjectKey;
private final DisplayMetrics mMetrics;
private final RenderResources mRenderResources;
+ private final Configuration mConfig;
private final ApplicationInfo mApplicationInfo;
+ private final IProjectCallback mProjectCallback;
+
+ private final BridgeWindowManager mIWindowManager;
private final Map<Object, Map<String, String>> mDefaultPropMaps =
new IdentityHashMap<Object, Map<String,String>>();
@@ -105,7 +110,6 @@
private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache;
private BridgeInflater mBridgeInflater;
- private final IProjectCallback mProjectCallback;
private BridgeContentResolver mContentResolver;
private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>();
@@ -113,28 +117,25 @@
/**
* @param projectKey An Object identifying the project. This is used for the cache mechanism.
* @param metrics the {@link DisplayMetrics}.
- * @param themeName The name of the theme to use.
- * @param projectResources the resources of the project. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the
- * map contains (String, {@link }) pairs where the key is the resource name,
- * and the value is the resource value.
- * @param frameworkResources the framework resources. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the map
- * contains (String, {@link ResourceValue}) pairs where the key is the resource name, and the
- * value is the resource value.
- * @param styleInheritanceMap
+ * @param renderResources the configured resources (both framework and projects) for this
+ * render.
* @param projectCallback
+ * @param config the Configuration object for this render.
* @param targetSdkVersion the targetSdkVersion of the application.
*/
public BridgeContext(Object projectKey, DisplayMetrics metrics,
RenderResources renderResources,
IProjectCallback projectCallback,
+ Configuration config,
int targetSdkVersion) {
mProjectKey = projectKey;
mMetrics = metrics;
mProjectCallback = projectCallback;
mRenderResources = renderResources;
+ mConfig = config;
+
+ mIWindowManager = new BridgeWindowManager(mConfig, metrics, Surface.ROTATION_0);
mFragments.mCurState = Fragment.CREATED;
mFragments.mActivity = this;
@@ -151,13 +152,12 @@
*/
public void initResources() {
AssetManager assetManager = AssetManager.getSystem();
- Configuration config = new Configuration();
mSystemResources = BridgeResources.initSystem(
this,
assetManager,
mMetrics,
- config,
+ mConfig,
mProjectCallback);
mTheme = mSystemResources.newTheme();
}
@@ -197,6 +197,10 @@
return mRenderResources;
}
+ public BridgeWindowManager getIWindowManager() {
+ return mIWindowManager;
+ }
+
public Map<String, String> getDefaultPropMap(Object key) {
return mDefaultPropMaps.get(key);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
new file mode 100644
index 0000000..13cd9ec
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.android;
+
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodClient;
+
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.Display_Delegate;
+import android.view.IApplicationToken;
+import android.view.IOnKeyguardExitResult;
+import android.view.IRotationWatcher;
+import android.view.IWindowManager;
+import android.view.IWindowSession;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.util.List;
+
+/**
+ * Basic implementation of {@link IWindowManager} so that {@link Display} (and
+ * {@link Display_Delegate}) can return a valid instance.
+ */
+public class BridgeWindowManager implements IWindowManager {
+
+ private final Configuration mConfig;
+ private final DisplayMetrics mMetrics;
+ private final int mRotation;
+
+ public BridgeWindowManager(Configuration config, DisplayMetrics metrics, int rotation) {
+ mConfig = config;
+ mMetrics = metrics;
+ mRotation = rotation;
+ }
+
+ // custom API.
+
+ public DisplayMetrics getMetrics() {
+ return mMetrics;
+ }
+
+ // ---- implementation of IWindowManager that we care about ----
+
+ public int getRotation() throws RemoteException {
+ return mRotation;
+ }
+
+ public int getMaximumSizeDimension() throws RemoteException {
+ return 0;
+ }
+
+ public void getDisplaySize(Point arg0) throws RemoteException {
+ }
+
+ // ---- unused implementation of IWindowManager ----
+
+ public boolean canStatusBarHide() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void addWindowToken(IBinder arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void clearForcedDisplaySize() throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void closeSystemDialogs(String arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void disableKeyguard(IBinder arg0, String arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void executeAppTransition() throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void exitKeyguardSecurely(IOnKeyguardExitResult arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void freezeRotation() throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public float getAnimationScale(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public float[] getAnimationScales() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int getAppOrientation(IApplicationToken arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getDPadKeycodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getDPadScancodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ public InputDevice getInputDevice(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int[] getInputDeviceIds() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int getKeycodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getKeycodeStateForDevice(int arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ public int getPendingAppTransition() throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ public int getScancodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getScancodeStateForDevice(int arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getSwitchState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getSwitchStateForDevice(int arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getTrackballKeycodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getTrackballScancodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public boolean hasKeys(int[] arg0, boolean[] arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean inKeyguardRestrictedInputMode() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean injectInputEventNoWait(InputEvent arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean injectKeyEvent(KeyEvent arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean injectPointerEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean injectTrackballEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean inputMethodClientHasFocus(IInputMethodClient arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isKeyguardLocked() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isKeyguardSecure() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isViewServerRunning() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public InputChannel monitorInput(String arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void moveAppToken(int arg0, IBinder arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void moveAppTokensToBottom(List<IBinder> arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void moveAppTokensToTop(List<IBinder> arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public IWindowSession openSession(IInputMethodClient arg0, IInputContext arg1)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void overridePendingAppTransition(String arg0, int arg1, int arg2)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void prepareAppTransition(int arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void reenableKeyguard(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void removeAppToken(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void removeWindowToken(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void resumeKeyDispatching(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Bitmap screenshotApplications(IBinder arg0, int arg1, int arg2) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void setAnimationScale(int arg0, float arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAnimationScales(float[] arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAppGroupId(IBinder arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAppOrientation(IApplicationToken arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3,
+ CharSequence arg4, int arg5, int arg6, int arg7, IBinder arg8, boolean arg9)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAppVisibility(IBinder arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAppWillBeHidden(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setEventDispatching(boolean arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setFocusedApp(IBinder arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setForcedDisplaySize(int arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setInTouchMode(boolean arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setNewConfiguration(Configuration arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setPointerSpeed(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setRotation(int arg0, boolean arg1, int arg2) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setStrictModeVisualIndicatorPreference(String arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void showStrictModeViolation(boolean arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void startAppFreezingScreen(IBinder arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean startViewServer(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void statusBarVisibilityChanged(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean stopViewServer() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void thawRotation() throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Configuration updateOrientationFromAppTokens(Configuration arg0, IBinder arg1)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int watchRotation(IRotationWatcher arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public IBinder asBinder() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 6194f5d..20f7195 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -27,10 +27,14 @@
import com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.resources.Density;
import com.android.resources.ResourceType;
+import com.android.resources.ScreenSize;
+import android.content.res.Configuration;
import android.os.HandlerThread_Delegate;
import android.util.DisplayMetrics;
+import android.view.ViewConfiguration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
@@ -94,24 +98,29 @@
// setup the display Metrics.
DisplayMetrics metrics = new DisplayMetrics();
metrics.densityDpi = mParams.getDensity().getDpiValue();
- metrics.density = metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
- metrics.scaledDensity = metrics.density;
- metrics.widthPixels = mParams.getScreenWidth();
- metrics.heightPixels = mParams.getScreenHeight();
- metrics.xdpi = mParams.getXdpi();
- metrics.ydpi = mParams.getYdpi();
+
+ metrics.density = metrics.noncompatDensity =
+ metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
+
+ metrics.scaledDensity = metrics.noncompatScaledDensity = metrics.density;
+
+ metrics.widthPixels = metrics.noncompatWidthPixels = mParams.getScreenWidth();
+ metrics.heightPixels = metrics.noncompatHeightPixels = mParams.getScreenHeight();
+ metrics.xdpi = metrics.noncompatXdpi = mParams.getXdpi();
+ metrics.ydpi = metrics.noncompatYdpi = mParams.getYdpi();
RenderResources resources = mParams.getResources();
// build the context
mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
- mParams.getProjectCallback(), mParams.getTargetSdkVersion());
+ mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion());
setUp();
return SUCCESS.createResult();
}
+
/**
* Prepares the scene for action.
* <p>
@@ -233,6 +242,9 @@
// quit HandlerThread created during this session.
HandlerThread_Delegate.cleanUp(sCurrentContext);
+ // clear the stored ViewConfiguration since the map is per density and not per context.
+ ViewConfiguration.sConfigurations.clear();
+
sCurrentContext = null;
Bridge.setLog(null);
@@ -281,6 +293,50 @@
}
}
+ private Configuration getConfiguration() {
+ Configuration config = new Configuration();
+
+ ScreenSize screenSize = mParams.getConfigScreenSize();
+ if (screenSize != null) {
+ switch (screenSize) {
+ case SMALL:
+ config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_SMALL;
+ break;
+ case NORMAL:
+ config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_NORMAL;
+ break;
+ case LARGE:
+ config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_LARGE;
+ break;
+ case XLARGE:
+ config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ break;
+ }
+ }
+
+ Density density = mParams.getDensity();
+ if (density == null) {
+ density = Density.MEDIUM;
+ }
+
+ config.screenWidthDp = mParams.getScreenWidth() / density.getDpiValue();
+ config.screenHeightDp = mParams.getScreenHeight() / density.getDpiValue();
+ if (config.screenHeightDp < config.screenWidthDp) {
+ config.smallestScreenWidthDp = config.screenHeightDp;
+ } else {
+ config.smallestScreenWidthDp = config.screenWidthDp;
+ }
+
+ // never run in compat mode:
+ config.compatScreenWidthDp = config.screenWidthDp;
+ config.compatScreenHeightDp = config.screenHeightDp;
+
+ // TODO: fill in more config info.
+
+ return config;
+ }
+
+
// --- FrameworkResourceIdProvider methods
@Override
diff --git a/tools/layoutlib/bridge/tests/.classpath b/tools/layoutlib/bridge/tests/.classpath
index 9cc2433d..027bc67 100644
--- a/tools/layoutlib/bridge/tests/.classpath
+++ b/tools/layoutlib/bridge/tests/.classpath
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="res"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/layoutlib_bridge"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 233f72ec..f385805 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -103,6 +103,7 @@
"android.os.Handler#sendMessageAtTime",
"android.os.HandlerThread#run",
"android.os.Build#getString",
+ "android.view.Display#getWindowManager",
"android.view.LayoutInflater#rInflate",
"android.view.LayoutInflater#parseInclude",
"android.view.View#isInEditMode",
@@ -154,6 +155,7 @@
"android.graphics.Xfermode",
"android.os.SystemClock",
"android.util.FloatMath",
+ "android.view.Display",
"libcore.icu.ICU",
};