summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/Android.mk3
-rw-r--r--services/audioflinger/AudioFlinger.cpp152
-rw-r--r--services/audioflinger/AudioFlinger.h33
-rw-r--r--services/camera/libcameraservice/CameraHardwareInterface.h5
-rw-r--r--services/input/EventHub.cpp11
-rw-r--r--services/input/EventHub.h2
-rw-r--r--services/input/InputDispatcher.cpp14
-rw-r--r--services/input/InputReader.cpp975
-rw-r--r--services/input/InputReader.h327
-rw-r--r--services/input/tests/InputReader_test.cpp41
-rw-r--r--services/java/com/android/server/ConnectivityService.java2
-rw-r--r--services/java/com/android/server/NetworkManagementService.java122
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityManagerService.java9
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java137
-rw-r--r--services/java/com/android/server/am/ConnectionRecord.java4
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java9
-rw-r--r--services/java/com/android/server/location/GeocoderProxy.java10
-rw-r--r--services/java/com/android/server/location/LocationProviderProxy.java11
-rw-r--r--services/java/com/android/server/net/NetworkAlertObserver.java44
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java315
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java32
-rw-r--r--services/java/com/android/server/usb/UsbDeviceManager.java29
-rw-r--r--services/java/com/android/server/wm/DragState.java4
-rw-r--r--services/java/com/android/server/wm/InputManager.java13
-rw-r--r--services/java/com/android/server/wm/ScreenRotationAnimation.java35
-rw-r--r--services/java/com/android/server/wm/StrictModeFlash.java3
-rw-r--r--services/java/com/android/server/wm/Watermark.java5
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java40
-rw-r--r--services/java/com/android/server/wm/WindowState.java4
-rw-r--r--services/jni/com_android_server_InputManager.cpp44
-rw-r--r--services/powermanager/Android.mk15
-rw-r--r--services/powermanager/IPowerManager.cpp71
-rw-r--r--services/surfaceflinger/Layer.cpp13
-rw-r--r--services/tests/servicestests/AndroidManifest.xml1
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java211
35 files changed, 1862 insertions, 884 deletions
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index a0407b9..fa49592 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -21,7 +21,8 @@ LOCAL_SHARED_LIBRARIES := \
libhardware \
libhardware_legacy \
libeffects \
- libdl
+ libdl \
+ libpowermanager
LOCAL_STATIC_LIBRARIES := \
libcpustats \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index cb1f921..4e068b2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -53,6 +53,7 @@
#include <audio_effects/effect_visualizer.h>
#include <cpustats/ThreadCpuUsage.h>
+#include <powermanager/PowerManager.h>
// #define DEBUG_CPU_USAGE 10 // log statistics every n wall clock seconds
// ----------------------------------------------------------------------------
@@ -887,14 +888,18 @@ void AudioFlinger::removeClient_l(pid_t pid)
AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id, uint32_t device)
: Thread(false),
mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
- mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false), mDevice(device)
+ mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false),
+ mDevice(device)
{
+ mDeathRecipient = new PMDeathRecipient(this);
}
AudioFlinger::ThreadBase::~ThreadBase()
{
mParamCond.broadcast();
mNewParameters.clear();
+ // do not lock the mutex in destructor
+ releaseWakeLock_l();
}
void AudioFlinger::ThreadBase::exit()
@@ -1061,6 +1066,69 @@ status_t AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String1
return NO_ERROR;
}
+void AudioFlinger::ThreadBase::acquireWakeLock()
+{
+ Mutex::Autolock _l(mLock);
+ acquireWakeLock_l();
+}
+
+void AudioFlinger::ThreadBase::acquireWakeLock_l()
+{
+ if (mPowerManager == 0) {
+ // use checkService() to avoid blocking if power service is not up yet
+ sp<IBinder> binder =
+ defaultServiceManager()->checkService(String16("power"));
+ if (binder == 0) {
+ LOGW("Thread %s cannot connect to the power manager service", mName);
+ } else {
+ mPowerManager = interface_cast<IPowerManager>(binder);
+ binder->linkToDeath(mDeathRecipient);
+ }
+ }
+ if (mPowerManager != 0) {
+ sp<IBinder> binder = new BBinder();
+ status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
+ binder,
+ String16(mName));
+ if (status == NO_ERROR) {
+ mWakeLockToken = binder;
+ }
+ LOGV("acquireWakeLock_l() %s status %d", mName, status);
+ }
+}
+
+void AudioFlinger::ThreadBase::releaseWakeLock()
+{
+ Mutex::Autolock _l(mLock);
+ releaseWakeLock();
+}
+
+void AudioFlinger::ThreadBase::releaseWakeLock_l()
+{
+ if (mWakeLockToken != 0) {
+ LOGV("releaseWakeLock_l() %s", mName);
+ if (mPowerManager != 0) {
+ mPowerManager->releaseWakeLock(mWakeLockToken, 0);
+ }
+ mWakeLockToken.clear();
+ }
+}
+
+void AudioFlinger::ThreadBase::clearPowerManager()
+{
+ Mutex::Autolock _l(mLock);
+ releaseWakeLock_l();
+ mPowerManager.clear();
+}
+
+void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& who)
+{
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ thread->clearPowerManager();
+ }
+ LOGW("power manager service died !!!");
+}
// ----------------------------------------------------------------------------
@@ -1072,6 +1140,8 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
{
+ snprintf(mName, kNameLength, "AudioOut_%d", id);
+
readOutputParameters();
mMasterVolume = mAudioFlinger->masterVolume();
@@ -1170,12 +1240,7 @@ status_t AudioFlinger::PlaybackThread::readyToRun()
void AudioFlinger::PlaybackThread::onFirstRef()
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "Playback Thread %p", this);
-
- run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
+ run(mName, ANDROID_PRIORITY_URGENT_AUDIO);
}
// PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held
@@ -1522,6 +1587,8 @@ bool AudioFlinger::MixerThread::threadLoop()
const CentralTendencyStatistics& stats = cpu.statistics();
#endif
+ acquireWakeLock();
+
while (!exitPending())
{
#ifdef DEBUG_CPU_USAGE
@@ -1585,10 +1652,12 @@ bool AudioFlinger::MixerThread::threadLoop()
if (exitPending()) break;
+ releaseWakeLock_l();
// wait until we have something to do...
LOGV("MixerThread %p TID %d going to sleep\n", this, gettid());
mWaitWorkCV.wait(mLock);
LOGV("MixerThread %p TID %d waking up\n", this, gettid());
+ acquireWakeLock_l();
if (mMasterMute == false) {
char value[PROPERTY_VALUE_MAX];
@@ -1689,6 +1758,8 @@ bool AudioFlinger::MixerThread::threadLoop()
mOutput->stream->common.standby(&mOutput->stream->common);
}
+ releaseWakeLock();
+
LOGV("MixerThread %p exiting", this);
return false;
}
@@ -2176,6 +2247,8 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
// hardware resources as soon as possible
nsecs_t standbyDelay = microseconds(activeSleepTime*2);
+ acquireWakeLock();
+
while (!exitPending())
{
bool rampVolume;
@@ -2215,9 +2288,11 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
if (exitPending()) break;
+ releaseWakeLock_l();
LOGV("DirectOutputThread %p TID %d going to sleep\n", this, gettid());
mWaitWorkCV.wait(mLock);
LOGV("DirectOutputThread %p TID %d waking up in active mode\n", this, gettid());
+ acquireWakeLock_l();
if (mMasterMute == false) {
char value[PROPERTY_VALUE_MAX];
@@ -2436,6 +2511,8 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
mOutput->stream->common.standby(&mOutput->stream->common);
}
+ releaseWakeLock();
+
LOGV("DirectOutputThread %p exiting", this);
return false;
}
@@ -2561,6 +2638,8 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
uint32_t sleepTime = idleSleepTime;
Vector< sp<EffectChain> > effectChains;
+ acquireWakeLock();
+
while (!exitPending())
{
processConfigEvents();
@@ -2601,9 +2680,12 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
if (exitPending()) break;
+ releaseWakeLock_l();
LOGV("DuplicatingThread %p TID %d going to sleep\n", this, gettid());
mWaitWorkCV.wait(mLock);
LOGV("DuplicatingThread %p TID %d waking up\n", this, gettid());
+ acquireWakeLock_l();
+
if (mMasterMute == false) {
char value[PROPERTY_VALUE_MAX];
property_get("ro.audio.silent", value, "0");
@@ -2690,6 +2772,8 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
effectChains.clear();
}
+ releaseWakeLock();
+
return false;
}
@@ -3814,6 +3898,9 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
mInput(input), mTrack(NULL), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
{
mType = ThreadBase::RECORD;
+
+ snprintf(mName, kNameLength, "AudioIn_%d", id);
+
mReqChannelCount = popcount(channels);
mReqSampleRate = sampleRate;
readInputParameters();
@@ -3831,12 +3918,7 @@ AudioFlinger::RecordThread::~RecordThread()
void AudioFlinger::RecordThread::onFirstRef()
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "Record Thread %p", this);
-
- run(buffer, PRIORITY_URGENT_AUDIO);
+ run(mName, PRIORITY_URGENT_AUDIO);
}
bool AudioFlinger::RecordThread::threadLoop()
@@ -3847,6 +3929,8 @@ bool AudioFlinger::RecordThread::threadLoop()
nsecs_t lastWarning = 0;
+ acquireWakeLock();
+
// start recording
while (!exitPending()) {
@@ -3863,10 +3947,12 @@ bool AudioFlinger::RecordThread::threadLoop()
if (exitPending()) break;
+ releaseWakeLock_l();
LOGV("RecordThread: loop stopping");
// go to sleep
mWaitWorkCV.wait(mLock);
LOGV("RecordThread: loop starting");
+ acquireWakeLock_l();
continue;
}
if (mActiveTrack != 0) {
@@ -3907,8 +3993,6 @@ bool AudioFlinger::RecordThread::threadLoop()
for (size_t i = 0; i < effectChains.size(); i ++) {
effectChains[i]->process_l();
}
- // enable changes in effect chain
- unlockEffectChains(effectChains);
buffer.frameCount = mFrameCount;
if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
@@ -4008,9 +4092,9 @@ bool AudioFlinger::RecordThread::threadLoop()
// clear the overflow.
usleep(kRecordThreadSleepUs);
}
- } else {
- unlockEffectChains(effectChains);
}
+ // enable changes in effect chain
+ unlockEffectChains(effectChains);
effectChains.clear();
}
@@ -4021,6 +4105,8 @@ bool AudioFlinger::RecordThread::threadLoop()
mStartStopCond.broadcast();
+ releaseWakeLock();
+
LOGV("RecordThread %p exiting", this);
return false;
}
@@ -5581,13 +5667,11 @@ size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle)
}
}
- // Release effect engine here so that it is done immediately. Otherwise it will be released
- // by the destructor when the last strong reference on the this object is released which can
- // happen after next process is called on this effect.
- if (size == 0 && mEffectInterface != NULL) {
- // release effect engine
- EffectRelease(mEffectInterface);
- mEffectInterface = NULL;
+ // Prevent calls to process() and other functions on effect interface from now on.
+ // The effect engine will be released by the destructor when the last strong reference on
+ // this object is released which can happen after next process is called.
+ if (size == 0) {
+ mState = DESTROYED;
}
return size;
@@ -5637,7 +5721,7 @@ void AudioFlinger::EffectModule::updateState() {
mState = IDLE;
}
break;
- default: //IDLE , ACTIVE
+ default: //IDLE , ACTIVE, DESTROYED
break;
}
}
@@ -5646,7 +5730,7 @@ void AudioFlinger::EffectModule::process()
{
Mutex::Autolock _l(mLock);
- if (mEffectInterface == NULL ||
+ if (mState == DESTROYED || mEffectInterface == NULL ||
mConfig.inputCfg.buffer.raw == NULL ||
mConfig.outputCfg.buffer.raw == NULL) {
return;
@@ -5822,6 +5906,12 @@ status_t AudioFlinger::EffectModule::start_l()
return status;
}
+status_t AudioFlinger::EffectModule::stop()
+{
+ Mutex::Autolock _l(mLock);
+ return stop_l();
+}
+
status_t AudioFlinger::EffectModule::stop_l()
{
if (mEffectInterface == NULL) {
@@ -5858,7 +5948,7 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode,
Mutex::Autolock _l(mLock);
// LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface);
- if (mEffectInterface == NULL) {
+ if (mState == DESTROYED || mEffectInterface == NULL) {
return NO_INIT;
}
status_t status = (*mEffectInterface)->command(mEffectInterface,
@@ -5907,6 +5997,8 @@ status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
case ACTIVE:
mState = STOPPING;
break;
+ case DESTROYED:
+ return NO_ERROR; // simply ignore as we are being destroyed
}
for (size_t i = 1; i < mHandles.size(); i++) {
sp<EffectHandle> h = mHandles[i].promote();
@@ -5928,6 +6020,7 @@ bool AudioFlinger::EffectModule::isEnabled()
case IDLE:
case STOPPING:
case STOPPED:
+ case DESTROYED:
default:
return false;
}
@@ -5943,6 +6036,7 @@ bool AudioFlinger::EffectModule::isProcessEnabled()
return true;
case IDLE:
case STARTING:
+ case DESTROYED:
default:
return false;
}
@@ -6544,6 +6638,10 @@ size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect)
for (i = 0; i < size; i++) {
if (effect == mEffects[i]) {
+ // calling stop here will remove pre-processing effect from the audio HAL.
+ // This is safe as we hold the EffectChain mutex which guarantees that we are not in
+ // the middle of a read from audio HAL
+ mEffects[i]->stop();
if (type == EFFECT_FLAG_TYPE_AUXILIARY) {
delete[] effect->inBuffer();
} else {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index e2cf946..7b6215f 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -43,6 +43,8 @@
#include "AudioBufferProvider.h"
+#include <powermanager/IPowerManager.h>
+
namespace android {
class audio_track_cblk_t;
@@ -287,6 +289,8 @@ private:
status_t dumpBase(int fd, const Vector<String16>& args);
status_t dumpEffectChains(int fd, const Vector<String16>& args);
+ void clearPowerManager();
+
// base for record and playback
class TrackBase : public AudioBufferProvider, public RefBase {
@@ -386,6 +390,21 @@ private:
int mParam;
};
+ class PMDeathRecipient : public IBinder::DeathRecipient {
+ public:
+ PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
+ virtual ~PMDeathRecipient() {}
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
+ private:
+ PMDeathRecipient(const PMDeathRecipient&);
+ PMDeathRecipient& operator = (const PMDeathRecipient&);
+
+ wp<ThreadBase> mThread;
+ };
+
virtual status_t initCheck() const = 0;
int type() const { return mType; }
uint32_t sampleRate() const;
@@ -462,6 +481,11 @@ private:
protected:
+ void acquireWakeLock();
+ void acquireWakeLock_l();
+ void releaseWakeLock();
+ void releaseWakeLock_l();
+
friend class Track;
friend class TrackBase;
friend class PlaybackThread;
@@ -490,6 +514,11 @@ private:
Vector< sp<EffectChain> > mEffectChains;
uint32_t mDevice; // output device for PlaybackThread
// input + output devices for RecordThread
+ static const int kNameLength = 32;
+ char mName[kNameLength];
+ sp<IPowerManager> mPowerManager;
+ sp<IBinder> mWakeLockToken;
+ sp<PMDeathRecipient> mDeathRecipient;
};
// --- PlaybackThread ---
@@ -995,7 +1024,8 @@ private:
STARTING,
ACTIVE,
STOPPING,
- STOPPED
+ STOPPED,
+ DESTROYED
};
int id() { return mId; }
@@ -1040,6 +1070,7 @@ private:
status_t setDevice(uint32_t device);
status_t setVolume(uint32_t *left, uint32_t *right, bool controller);
status_t setMode(uint32_t mode);
+ status_t stop();
status_t dump(int fd, const Vector<String16>& args);
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h
index a583aad..09e88c4 100644
--- a/services/camera/libcameraservice/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/CameraHardwareInterface.h
@@ -386,7 +386,10 @@ public:
if (mDevice->ops->get_parameters) {
char *temp = mDevice->ops->get_parameters(mDevice);
String8 str_parms(temp);
- free(temp);
+ if (mDevice->ops->put_parameters)
+ mDevice->ops->put_parameters(mDevice, temp);
+ else
+ free(temp);
parms.unflatten(str_parms);
}
return parms;
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index ca2540b..7ea3de2 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -460,6 +460,17 @@ void EventHub::setExcludedDevices(const Vector<String8>& devices) {
mExcludedDevices = devices;
}
+bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device && scanCode >= 0 && scanCode <= KEY_MAX) {
+ if (test_bit(scanCode, device->keyBitmask)) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 695dfdf..293a1a0 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -195,6 +195,7 @@ public:
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
uint8_t* outFlags) const = 0;
+ virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0;
virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;
virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0;
@@ -246,6 +247,7 @@ public:
virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize);
+ virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const;
virtual bool hasLed(int32_t deviceId, int32_t led) const;
virtual void setLedState(int32_t deviceId, int32_t led, bool on);
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 039b003..af13945 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -998,8 +998,7 @@ void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTi
void InputDispatcher::resetTargetsLocked() {
mCurrentInputTargetsValid = false;
mCurrentInputTargets.clear();
- mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
- mInputTargetWaitApplicationHandle.clear();
+ resetANRTimeoutsLocked();
}
void InputDispatcher::commitTargetsLocked() {
@@ -1110,6 +1109,7 @@ void InputDispatcher::resetANRTimeoutsLocked() {
// Reset input target wait timeout.
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
+ mInputTargetWaitApplicationHandle.clear();
}
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
@@ -3226,8 +3226,14 @@ void InputDispatcher::setFocusedApplication(
AutoMutex _l(mLock);
if (inputApplicationHandle != NULL && inputApplicationHandle->update()) {
- mFocusedApplicationHandle = inputApplicationHandle;
- } else {
+ if (mFocusedApplicationHandle != inputApplicationHandle) {
+ if (mFocusedApplicationHandle != NULL) {
+ resetTargetsLocked();
+ }
+ mFocusedApplicationHandle = inputApplicationHandle;
+ }
+ } else if (mFocusedApplicationHandle != NULL) {
+ resetTargetsLocked();
mFocusedApplicationHandle.clear();
}
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index c9fac81..db312ad 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -151,30 +151,6 @@ static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0;
}
-static uint32_t getButtonStateForScanCode(int32_t scanCode) {
- // Currently all buttons are mapped to the primary button.
- switch (scanCode) {
- case BTN_LEFT:
- return AMOTION_EVENT_BUTTON_PRIMARY;
- case BTN_RIGHT:
- case BTN_STYLUS:
- return AMOTION_EVENT_BUTTON_SECONDARY;
- case BTN_MIDDLE:
- case BTN_STYLUS2:
- return AMOTION_EVENT_BUTTON_TERTIARY;
- case BTN_SIDE:
- return AMOTION_EVENT_BUTTON_BACK;
- case BTN_FORWARD:
- case BTN_EXTRA:
- return AMOTION_EVENT_BUTTON_FORWARD;
- case BTN_BACK:
- return AMOTION_EVENT_BUTTON_BACK;
- case BTN_TASK:
- default:
- return 0;
- }
-}
-
// Returns true if the pointer should be reported as being down given the specified
// button states. This determines whether the event is reported as a touch event.
static bool isPointerDown(int32_t buttonState) {
@@ -1007,6 +983,378 @@ void InputDevice::fadePointer() {
}
+// --- CursorButtonAccumulator ---
+
+CursorButtonAccumulator::CursorButtonAccumulator() {
+ clearButtons();
+}
+
+void CursorButtonAccumulator::clearButtons() {
+ mBtnLeft = 0;
+ mBtnRight = 0;
+ mBtnMiddle = 0;
+ mBtnBack = 0;
+ mBtnSide = 0;
+ mBtnForward = 0;
+ mBtnExtra = 0;
+ mBtnTask = 0;
+}
+
+void CursorButtonAccumulator::process(const RawEvent* rawEvent) {
+ if (rawEvent->type == EV_KEY) {
+ switch (rawEvent->scanCode) {
+ case BTN_LEFT:
+ mBtnLeft = rawEvent->value;
+ break;
+ case BTN_RIGHT:
+ mBtnRight = rawEvent->value;
+ break;
+ case BTN_MIDDLE:
+ mBtnMiddle = rawEvent->value;
+ break;
+ case BTN_BACK:
+ mBtnBack = rawEvent->value;
+ break;
+ case BTN_SIDE:
+ mBtnSide = rawEvent->value;
+ break;
+ case BTN_FORWARD:
+ mBtnForward = rawEvent->value;
+ break;
+ case BTN_EXTRA:
+ mBtnExtra = rawEvent->value;
+ break;
+ case BTN_TASK:
+ mBtnTask = rawEvent->value;
+ break;
+ }
+ }
+}
+
+uint32_t CursorButtonAccumulator::getButtonState() const {
+ uint32_t result = 0;
+ if (mBtnLeft) {
+ result |= AMOTION_EVENT_BUTTON_PRIMARY;
+ }
+ if (mBtnRight) {
+ result |= AMOTION_EVENT_BUTTON_SECONDARY;
+ }
+ if (mBtnMiddle) {
+ result |= AMOTION_EVENT_BUTTON_TERTIARY;
+ }
+ if (mBtnBack || mBtnSide) {
+ result |= AMOTION_EVENT_BUTTON_BACK;
+ }
+ if (mBtnForward || mBtnExtra) {
+ result |= AMOTION_EVENT_BUTTON_FORWARD;
+ }
+ return result;
+}
+
+
+// --- CursorMotionAccumulator ---
+
+CursorMotionAccumulator::CursorMotionAccumulator() :
+ mHaveRelWheel(false), mHaveRelHWheel(false) {
+ clearRelativeAxes();
+}
+
+void CursorMotionAccumulator::configure(InputDevice* device) {
+ mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL);
+ mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL);
+}
+
+void CursorMotionAccumulator::clearRelativeAxes() {
+ mRelX = 0;
+ mRelY = 0;
+ mRelWheel = 0;
+ mRelHWheel = 0;
+}
+
+void CursorMotionAccumulator::process(const RawEvent* rawEvent) {
+ if (rawEvent->type == EV_REL) {
+ switch (rawEvent->scanCode) {
+ case REL_X:
+ mRelX = rawEvent->value;
+ break;
+ case REL_Y:
+ mRelY = rawEvent->value;
+ break;
+ case REL_WHEEL:
+ mRelWheel = rawEvent->value;
+ break;
+ case REL_HWHEEL:
+ mRelHWheel = rawEvent->value;
+ break;
+ }
+ }
+}
+
+
+// --- TouchButtonAccumulator ---
+
+TouchButtonAccumulator::TouchButtonAccumulator() :
+ mHaveBtnTouch(false) {
+ clearButtons();
+}
+
+void TouchButtonAccumulator::configure(InputDevice* device) {
+ mHaveBtnTouch = device->getEventHub()->hasScanCode(device->getId(), BTN_TOUCH);
+}
+
+void TouchButtonAccumulator::clearButtons() {
+ mBtnTouch = 0;
+ mBtnStylus = 0;
+ mBtnStylus2 = 0;
+ mBtnToolFinger = 0;
+ mBtnToolPen = 0;
+ mBtnToolRubber = 0;
+}
+
+void TouchButtonAccumulator::process(const RawEvent* rawEvent) {
+ if (rawEvent->type == EV_KEY) {
+ switch (rawEvent->scanCode) {
+ case BTN_TOUCH:
+ mBtnTouch = rawEvent->value;
+ break;
+ case BTN_STYLUS:
+ mBtnStylus = rawEvent->value;
+ break;
+ case BTN_STYLUS2:
+ mBtnStylus2 = rawEvent->value;
+ break;
+ case BTN_TOOL_FINGER:
+ mBtnToolFinger = rawEvent->value;
+ break;
+ case BTN_TOOL_PEN:
+ mBtnToolPen = rawEvent->value;
+ break;
+ case BTN_TOOL_RUBBER:
+ mBtnToolRubber = rawEvent->value;
+ break;
+ }
+ }
+}
+
+uint32_t TouchButtonAccumulator::getButtonState() const {
+ uint32_t result = 0;
+ if (mBtnStylus) {
+ result |= AMOTION_EVENT_BUTTON_SECONDARY;
+ }
+ if (mBtnStylus2) {
+ result |= AMOTION_EVENT_BUTTON_TERTIARY;
+ }
+ return result;
+}
+
+int32_t TouchButtonAccumulator::getToolType() const {
+ if (mBtnToolRubber) {
+ return AMOTION_EVENT_TOOL_TYPE_ERASER;
+ }
+ if (mBtnToolPen) {
+ return AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ }
+ if (mBtnToolFinger) {
+ return AMOTION_EVENT_TOOL_TYPE_FINGER;
+ }
+ return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
+}
+
+bool TouchButtonAccumulator::isActive() const {
+ return mBtnTouch || mBtnToolFinger || mBtnToolPen
+ || mBtnToolRubber || mBtnStylus || mBtnStylus2;
+}
+
+bool TouchButtonAccumulator::isHovering() const {
+ return mHaveBtnTouch && !mBtnTouch;
+}
+
+
+// --- SingleTouchMotionAccumulator ---
+
+SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() {
+ clearAbsoluteAxes();
+}
+
+void SingleTouchMotionAccumulator::clearAbsoluteAxes() {
+ mAbsX = 0;
+ mAbsY = 0;
+ mAbsPressure = 0;
+ mAbsToolWidth = 0;
+ mAbsDistance = 0;
+}
+
+void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) {
+ if (rawEvent->type == EV_ABS) {
+ switch (rawEvent->scanCode) {
+ case ABS_X:
+ mAbsX = rawEvent->value;
+ break;
+ case ABS_Y:
+ mAbsY = rawEvent->value;
+ break;
+ case ABS_PRESSURE:
+ mAbsPressure = rawEvent->value;
+ break;
+ case ABS_TOOL_WIDTH:
+ mAbsToolWidth = rawEvent->value;
+ break;
+ case ABS_DISTANCE:
+ mAbsDistance = rawEvent->value;
+ break;
+ }
+ }
+}
+
+
+// --- MultiTouchMotionAccumulator ---
+
+MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() :
+ mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false) {
+}
+
+MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() {
+ delete[] mSlots;
+}
+
+void MultiTouchMotionAccumulator::configure(size_t slotCount, bool usingSlotsProtocol) {
+ mSlotCount = slotCount;
+ mUsingSlotsProtocol = usingSlotsProtocol;
+
+ delete[] mSlots;
+ mSlots = new Slot[slotCount];
+}
+
+void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
+ for (size_t i = 0; i < mSlotCount; i++) {
+ mSlots[i].clearIfInUse();
+ }
+ mCurrentSlot = initialSlot;
+}
+
+void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
+ if (rawEvent->type == EV_ABS) {
+ bool newSlot = false;
+ if (mUsingSlotsProtocol) {
+ if (rawEvent->scanCode == ABS_MT_SLOT) {
+ mCurrentSlot = rawEvent->value;
+ newSlot = true;
+ }
+ } else if (mCurrentSlot < 0) {
+ mCurrentSlot = 0;
+ }
+
+ if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
+#if DEBUG_POINTERS
+ if (newSlot) {
+ LOGW("MultiTouch device emitted invalid slot index %d but it "
+ "should be between 0 and %d; ignoring this slot.",
+ mCurrentSlot, mSlotCount - 1);
+ }
+#endif
+ } else {
+ Slot* slot = &mSlots[mCurrentSlot];
+
+ switch (rawEvent->scanCode) {
+ case ABS_MT_POSITION_X:
+ slot->mInUse = true;
+ slot->mAbsMTPositionX = rawEvent->value;
+ break;
+ case ABS_MT_POSITION_Y:
+ slot->mInUse = true;
+ slot->mAbsMTPositionY = rawEvent->value;
+ break;
+ case ABS_MT_TOUCH_MAJOR:
+ slot->mInUse = true;
+ slot->mAbsMTTouchMajor = rawEvent->value;
+ break;
+ case ABS_MT_TOUCH_MINOR:
+ slot->mInUse = true;
+ slot->mAbsMTTouchMinor = rawEvent->value;
+ slot->mHaveAbsMTTouchMinor = true;
+ break;
+ case ABS_MT_WIDTH_MAJOR:
+ slot->mInUse = true;
+ slot->mAbsMTWidthMajor = rawEvent->value;
+ break;
+ case ABS_MT_WIDTH_MINOR:
+ slot->mInUse = true;
+ slot->mAbsMTWidthMinor = rawEvent->value;
+ slot->mHaveAbsMTWidthMinor = true;
+ break;
+ case ABS_MT_ORIENTATION:
+ slot->mInUse = true;
+ slot->mAbsMTOrientation = rawEvent->value;
+ break;
+ case ABS_MT_TRACKING_ID:
+ if (mUsingSlotsProtocol && rawEvent->value < 0) {
+ slot->clearIfInUse();
+ } else {
+ slot->mInUse = true;
+ slot->mAbsMTTrackingId = rawEvent->value;
+ }
+ break;
+ case ABS_MT_PRESSURE:
+ slot->mInUse = true;
+ slot->mAbsMTPressure = rawEvent->value;
+ break;
+ case ABS_MT_TOOL_TYPE:
+ slot->mInUse = true;
+ slot->mAbsMTToolType = rawEvent->value;
+ slot->mHaveAbsMTToolType = true;
+ break;
+ }
+ }
+ } else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_MT_REPORT) {
+ // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
+ mCurrentSlot += 1;
+ }
+}
+
+
+// --- MultiTouchMotionAccumulator::Slot ---
+
+MultiTouchMotionAccumulator::Slot::Slot() {
+ clear();
+}
+
+void MultiTouchMotionAccumulator::Slot::clearIfInUse() {
+ if (mInUse) {
+ clear();
+ }
+}
+
+void MultiTouchMotionAccumulator::Slot::clear() {
+ mInUse = false;
+ mHaveAbsMTTouchMinor = false;
+ mHaveAbsMTWidthMinor = false;
+ mHaveAbsMTToolType = false;
+ mAbsMTPositionX = 0;
+ mAbsMTPositionY = 0;
+ mAbsMTTouchMajor = 0;
+ mAbsMTTouchMinor = 0;
+ mAbsMTWidthMajor = 0;
+ mAbsMTWidthMinor = 0;
+ mAbsMTOrientation = 0;
+ mAbsMTTrackingId = -1;
+ mAbsMTPressure = 0;
+ mAbsMTToolType = 0;
+ mAbsMTDistance = 0;
+}
+
+int32_t MultiTouchMotionAccumulator::Slot::getToolType() const {
+ if (mHaveAbsMTToolType) {
+ switch (mAbsMTToolType) {
+ case MT_TOOL_FINGER:
+ return AMOTION_EVENT_TOOL_TYPE_FINGER;
+ case MT_TOOL_PEN:
+ return AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ }
+ }
+ return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
+}
+
+
// --- InputMapper ---
InputMapper::InputMapper(InputDevice* device) :
@@ -1157,7 +1505,10 @@ void KeyboardInputMapper::configureParameters() {
getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
mParameters.orientationAware);
- mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1;
+ mParameters.associatedDisplayId = -1;
+ if (mParameters.orientationAware) {
+ mParameters.associatedDisplayId = 0;
+ }
}
void KeyboardInputMapper::dumpParameters(String8& dump) {
@@ -1229,7 +1580,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
int32_t orientation;
if (!getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
- NULL, NULL, & orientation)) {
+ false /*external*/, NULL, NULL, & orientation)) {
orientation = DISPLAY_ORIENTATION_0;
}
@@ -1399,10 +1750,10 @@ void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
}
info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f);
- if (mHaveVWheel) {
+ if (mCursorMotionAccumulator.haveRelativeVWheel()) {
info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
}
- if (mHaveHWheel) {
+ if (mCursorMotionAccumulator.haveRelativeHWheel()) {
info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
}
}
@@ -1416,8 +1767,10 @@ void CursorInputMapper::dump(String8& dump) {
dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale);
dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
- dump.appendFormat(INDENT3 "HaveVWheel: %s\n", toString(mHaveVWheel));
- dump.appendFormat(INDENT3 "HaveHWheel: %s\n", toString(mHaveHWheel));
+ dump.appendFormat(INDENT3 "HaveVWheel: %s\n",
+ toString(mCursorMotionAccumulator.haveRelativeVWheel()));
+ dump.appendFormat(INDENT3 "HaveHWheel: %s\n",
+ toString(mCursorMotionAccumulator.haveRelativeHWheel()));
dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mLocked.buttonState);
@@ -1430,6 +1783,8 @@ void CursorInputMapper::configure(const InputReaderConfiguration* config, uint32
InputMapper::configure(config, changes);
if (!changes) { // first time only
+ mCursorMotionAccumulator.configure(getDevice());
+
// Configure basic parameters.
configureParameters();
@@ -1454,9 +1809,6 @@ void CursorInputMapper::configure(const InputReaderConfiguration* config, uint32
mVWheelScale = 1.0f;
mHWheelScale = 1.0f;
-
- mHaveVWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_WHEEL);
- mHaveHWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_HWHEEL);
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
@@ -1481,8 +1833,10 @@ void CursorInputMapper::configureParameters() {
getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
mParameters.orientationAware);
- mParameters.associatedDisplayId = mParameters.mode == Parameters::MODE_POINTER
- || mParameters.orientationAware ? 0 : -1;
+ mParameters.associatedDisplayId = -1;
+ if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
+ mParameters.associatedDisplayId = 0;
+ }
}
void CursorInputMapper::dumpParameters(String8& dump) {
@@ -1506,7 +1860,8 @@ void CursorInputMapper::dumpParameters(String8& dump) {
}
void CursorInputMapper::initializeLocked() {
- mAccumulator.clear();
+ mCursorButtonAccumulator.clearButtons();
+ mCursorMotionAccumulator.clearRelativeAxes();
mLocked.buttonState = 0;
mLocked.downTime = 0;
@@ -1532,10 +1887,8 @@ void CursorInputMapper::reset() {
// Synthesize button up event on reset.
nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
- mAccumulator.clear();
- mAccumulator.buttonDown = 0;
- mAccumulator.buttonUp = buttonState;
- mAccumulator.fields = Accumulator::FIELD_BUTTONS;
+ mCursorButtonAccumulator.clearButtons();
+ mCursorMotionAccumulator.clearRelativeAxes();
sync(when);
}
@@ -1543,64 +1896,15 @@ void CursorInputMapper::reset() {
}
void CursorInputMapper::process(const RawEvent* rawEvent) {
- switch (rawEvent->type) {
- case EV_KEY: {
- int32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode);
- if (buttonState) {
- if (rawEvent->value) {
- mAccumulator.buttonDown = buttonState;
- mAccumulator.buttonUp = 0;
- } else {
- mAccumulator.buttonDown = 0;
- mAccumulator.buttonUp = buttonState;
- }
- mAccumulator.fields |= Accumulator::FIELD_BUTTONS;
+ mCursorButtonAccumulator.process(rawEvent);
+ mCursorMotionAccumulator.process(rawEvent);
- // Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and
- // we need to ensure that we report the up/down promptly.
- sync(rawEvent->when);
- break;
- }
- break;
- }
-
- case EV_REL:
- switch (rawEvent->scanCode) {
- case REL_X:
- mAccumulator.fields |= Accumulator::FIELD_REL_X;
- mAccumulator.relX = rawEvent->value;
- break;
- case REL_Y:
- mAccumulator.fields |= Accumulator::FIELD_REL_Y;
- mAccumulator.relY = rawEvent->value;
- break;
- case REL_WHEEL:
- mAccumulator.fields |= Accumulator::FIELD_REL_WHEEL;
- mAccumulator.relWheel = rawEvent->value;
- break;
- case REL_HWHEEL:
- mAccumulator.fields |= Accumulator::FIELD_REL_HWHEEL;
- mAccumulator.relHWheel = rawEvent->value;
- break;
- }
- break;
-
- case EV_SYN:
- switch (rawEvent->scanCode) {
- case SYN_REPORT:
- sync(rawEvent->when);
- break;
- }
- break;
+ if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {
+ sync(rawEvent->when);
}
}
void CursorInputMapper::sync(nsecs_t when) {
- uint32_t fields = mAccumulator.fields;
- if (fields == 0) {
- return; // no new state changes, so nothing to do
- }
-
int32_t motionEventAction;
int32_t lastButtonState, currentButtonState;
PointerProperties pointerProperties;
@@ -1611,34 +1915,21 @@ void CursorInputMapper::sync(nsecs_t when) {
AutoMutex _l(mLock);
lastButtonState = mLocked.buttonState;
+ currentButtonState = mCursorButtonAccumulator.getButtonState();
+ mLocked.buttonState = currentButtonState;
- bool down, downChanged;
- bool wasDown = isPointerDown(mLocked.buttonState);
- bool buttonsChanged = fields & Accumulator::FIELD_BUTTONS;
- if (buttonsChanged) {
- mLocked.buttonState = (mLocked.buttonState | mAccumulator.buttonDown)
- & ~mAccumulator.buttonUp;
-
- down = isPointerDown(mLocked.buttonState);
-
- if (!wasDown && down) {
- mLocked.downTime = when;
- downChanged = true;
- } else if (wasDown && !down) {
- downChanged = true;
- } else {
- downChanged = false;
- }
+ bool wasDown = isPointerDown(lastButtonState);
+ bool down = isPointerDown(currentButtonState);
+ bool downChanged;
+ if (!wasDown && down) {
+ mLocked.downTime = when;
+ downChanged = true;
+ } else if (wasDown && !down) {
+ downChanged = true;
} else {
- down = wasDown;
downChanged = false;
}
-
- currentButtonState = mLocked.buttonState;
-
downTime = mLocked.downTime;
- float deltaX = fields & Accumulator::FIELD_REL_X ? mAccumulator.relX * mXScale : 0.0f;
- float deltaY = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f;
if (downChanged) {
motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
@@ -1648,13 +1939,16 @@ void CursorInputMapper::sync(nsecs_t when) {
motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
}
+ float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
+ float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
+
if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0
&& (deltaX != 0.0f || deltaY != 0.0f)) {
// Rotate motion based on display orientation if needed.
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
int32_t orientation;
if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
- NULL, NULL, & orientation)) {
+ false /*external*/, NULL, NULL, & orientation)) {
orientation = DISPLAY_ORIENTATION_0;
}
@@ -1667,25 +1961,17 @@ void CursorInputMapper::sync(nsecs_t when) {
pointerCoords.clear();
- if (mHaveVWheel && (fields & Accumulator::FIELD_REL_WHEEL)) {
- vscroll = mAccumulator.relWheel;
- } else {
- vscroll = 0;
- }
- mWheelYVelocityControl.move(when, NULL, &vscroll);
+ vscroll = mCursorMotionAccumulator.getRelativeVWheel();
+ hscroll = mCursorMotionAccumulator.getRelativeHWheel();
- if (mHaveHWheel && (fields & Accumulator::FIELD_REL_HWHEEL)) {
- hscroll = mAccumulator.relHWheel;
- } else {
- hscroll = 0;
- }
+ mWheelYVelocityControl.move(when, NULL, &vscroll);
mWheelXVelocityControl.move(when, &hscroll, NULL);
mPointerVelocityControl.move(when, &deltaX, &deltaY);
if (mPointerController != NULL) {
if (deltaX != 0 || deltaY != 0 || vscroll != 0 || hscroll != 0
- || buttonsChanged) {
+ || currentButtonState != lastButtonState) {
mPointerController->setPresentation(
PointerControllerInterface::PRESENTATION_POINTER);
@@ -1693,8 +1979,8 @@ void CursorInputMapper::sync(nsecs_t when) {
mPointerController->move(deltaX, deltaY);
}
- if (buttonsChanged) {
- mPointerController->setButtonState(mLocked.buttonState);
+ if (currentButtonState != lastButtonState) {
+ mPointerController->setButtonState(currentButtonState);
}
mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
@@ -1755,7 +2041,7 @@ void CursorInputMapper::sync(nsecs_t when) {
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
policyFlags, lastButtonState, currentButtonState);
- mAccumulator.clear();
+ mCursorMotionAccumulator.clearRelativeAxes();
}
int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
@@ -1881,10 +2167,11 @@ void TouchInputMapper::dump(String8& dump) {
const PointerData& pointer = mLastTouch.pointers[i];
dump.appendFormat(INDENT5 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
"touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
- "orientation=%d, distance=%d, isStylus=%s\n", i,
+ "orientation=%d, distance=%d, toolType=%d, isHovering=%s\n", i,
pointer.id, pointer.x, pointer.y, pointer.pressure,
pointer.touchMajor, pointer.touchMinor, pointer.toolMajor, pointer.toolMinor,
- pointer.orientation, pointer.distance, toString(pointer.isStylus));
+ pointer.orientation, pointer.distance,
+ pointer.toolType, toString(pointer.isHovering));
}
if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
@@ -2026,10 +2313,16 @@ void TouchInputMapper::configureParameters() {
getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
mParameters.orientationAware);
- mParameters.associatedDisplayId = mParameters.orientationAware
+ mParameters.associatedDisplayId = -1;
+ mParameters.associatedDisplayIsExternal = false;
+ if (mParameters.orientationAware
|| mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
- || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
- ? 0 : -1;
+ || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+ mParameters.associatedDisplayIsExternal =
+ mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
+ && getDevice()->isExternal();
+ mParameters.associatedDisplayId = 0;
+ }
}
void TouchInputMapper::dumpParameters(String8& dump) {
@@ -2111,6 +2404,7 @@ bool TouchInputMapper::configureSurfaceLocked() {
if (mParameters.associatedDisplayId >= 0) {
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
+ mParameters.associatedDisplayIsExternal,
&mLocked.associatedDisplayWidth, &mLocked.associatedDisplayHeight,
&mLocked.associatedDisplayOrientation)) {
return false;
@@ -2924,6 +3218,7 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
calculatePointerIds();
}
+ // Handle initial down events.
uint32_t policyFlags = 0;
if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) {
if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
@@ -3420,7 +3715,7 @@ void TouchInputMapper::prepareTouches(float* outXPrecision, float* outYPrecision
PointerProperties& properties = mCurrentTouchProperties[i];
properties.clear();
properties.id = mCurrentTouch.pointers[i].id;
- properties.toolType = getTouchToolType(mCurrentTouch.pointers[i].isStylus);
+ properties.toolType = mCurrentTouch.pointers[i].toolType;
}
*outXPrecision = mLocked.orientedXPrecision;
@@ -3604,7 +3899,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
PointerProperties pointerProperties;
pointerProperties.clear();
pointerProperties.id = 0;
- pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER;
+ pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
PointerCoords pointerCoords;
pointerCoords.clear();
@@ -3838,8 +4133,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
mPointerGesture.currentGestureProperties[0].clear();
mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
- mPointerGesture.currentGestureProperties[0].toolType =
- AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER;
+ mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
mPointerGesture.currentGestureCoords[0].clear();
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
@@ -3880,7 +4174,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureProperties[0].id =
mPointerGesture.activeGestureId;
mPointerGesture.currentGestureProperties[0].toolType =
- AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER;
+ AMOTION_EVENT_TOOL_TYPE_FINGER;
mPointerGesture.currentGestureCoords[0].clear();
mPointerGesture.currentGestureCoords[0].setAxisValue(
AMOTION_EVENT_AXIS_X, mPointerGesture.tapX);
@@ -3993,7 +4287,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureProperties[0].clear();
mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
mPointerGesture.currentGestureProperties[0].toolType =
- AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER;
+ AMOTION_EVENT_TOOL_TYPE_FINGER;
mPointerGesture.currentGestureCoords[0].clear();
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
@@ -4240,7 +4534,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureProperties[0].clear();
mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
mPointerGesture.currentGestureProperties[0].toolType =
- AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER;
+ AMOTION_EVENT_TOOL_TYPE_FINGER;
mPointerGesture.currentGestureCoords[0].clear();
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
mPointerGesture.referenceGestureX);
@@ -4331,7 +4625,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureProperties[i].clear();
mPointerGesture.currentGestureProperties[i].id = gestureId;
mPointerGesture.currentGestureProperties[i].toolType =
- AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER;
+ AMOTION_EVENT_TOOL_TYPE_FINGER;
mPointerGesture.currentGestureCoords[i].clear();
mPointerGesture.currentGestureCoords[i].setAxisValue(
AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX);
@@ -4473,15 +4767,6 @@ void TouchInputMapper::fadePointer() {
} // release lock
}
-int32_t TouchInputMapper::getTouchToolType(bool isStylus) const {
- if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
- return isStylus ? AMOTION_EVENT_TOOL_TYPE_STYLUS : AMOTION_EVENT_TOOL_TYPE_FINGER;
- } else {
- return isStylus ? AMOTION_EVENT_TOOL_TYPE_INDIRECT_STYLUS
- : AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER;
- }
-}
-
bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) {
return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue
&& y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue;
@@ -4760,14 +5045,9 @@ SingleTouchInputMapper::~SingleTouchInputMapper() {
}
void SingleTouchInputMapper::clearState() {
- mAccumulator.clear();
-
- mDown = false;
- mX = 0;
- mY = 0;
- mPressure = 0; // default to 0 for devices that don't report pressure
- mToolWidth = 0; // default to 0 for devices that don't report tool width
- mButtonState = 0;
+ mCursorButtonAccumulator.clearButtons();
+ mTouchButtonAccumulator.clearButtons();
+ mSingleTouchMotionAccumulator.clearAbsoluteAxes();
}
void SingleTouchInputMapper::reset() {
@@ -4777,144 +5057,79 @@ void SingleTouchInputMapper::reset() {
}
void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
- switch (rawEvent->type) {
- case EV_KEY:
- switch (rawEvent->scanCode) {
- case BTN_TOUCH:
- mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH;
- mAccumulator.btnTouch = rawEvent->value != 0;
- // Don't sync immediately. Wait until the next SYN_REPORT since we might
- // not have received valid position information yet. This logic assumes that
- // BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet.
- break;
- default:
- if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
- int32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode);
- if (buttonState) {
- if (rawEvent->value) {
- mAccumulator.buttonDown |= buttonState;
- } else {
- mAccumulator.buttonUp |= buttonState;
- }
- mAccumulator.fields |= Accumulator::FIELD_BUTTONS;
- }
- }
- break;
- }
- break;
-
- case EV_ABS:
- switch (rawEvent->scanCode) {
- case ABS_X:
- mAccumulator.fields |= Accumulator::FIELD_ABS_X;
- mAccumulator.absX = rawEvent->value;
- break;
- case ABS_Y:
- mAccumulator.fields |= Accumulator::FIELD_ABS_Y;
- mAccumulator.absY = rawEvent->value;
- break;
- case ABS_PRESSURE:
- mAccumulator.fields |= Accumulator::FIELD_ABS_PRESSURE;
- mAccumulator.absPressure = rawEvent->value;
- break;
- case ABS_TOOL_WIDTH:
- mAccumulator.fields |= Accumulator::FIELD_ABS_TOOL_WIDTH;
- mAccumulator.absToolWidth = rawEvent->value;
- break;
- }
- break;
+ mCursorButtonAccumulator.process(rawEvent);
+ mTouchButtonAccumulator.process(rawEvent);
+ mSingleTouchMotionAccumulator.process(rawEvent);
- case EV_SYN:
- switch (rawEvent->scanCode) {
- case SYN_REPORT:
- sync(rawEvent->when);
- break;
- }
- break;
+ if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {
+ sync(rawEvent->when);
}
}
void SingleTouchInputMapper::sync(nsecs_t when) {
- uint32_t fields = mAccumulator.fields;
- if (fields == 0) {
- return; // no new state changes, so nothing to do
- }
-
- if (fields & Accumulator::FIELD_BTN_TOUCH) {
- mDown = mAccumulator.btnTouch;
- }
-
- if (fields & Accumulator::FIELD_ABS_X) {
- mX = mAccumulator.absX;
- }
-
- if (fields & Accumulator::FIELD_ABS_Y) {
- mY = mAccumulator.absY;
- }
-
- if (fields & Accumulator::FIELD_ABS_PRESSURE) {
- mPressure = mAccumulator.absPressure;
- }
-
- if (fields & Accumulator::FIELD_ABS_TOOL_WIDTH) {
- mToolWidth = mAccumulator.absToolWidth;
- }
-
- if (fields & Accumulator::FIELD_BUTTONS) {
- mButtonState = (mButtonState | mAccumulator.buttonDown) & ~mAccumulator.buttonUp;
- }
-
mCurrentTouch.clear();
- if (mDown) {
+ if (mTouchButtonAccumulator.isActive()) {
+ uint32_t buttonState = mTouchButtonAccumulator.getButtonState();
+ bool isHovering = mTouchButtonAccumulator.isHovering();
+ if (mSingleTouchMotionAccumulator.getAbsoluteDistance() > 0) {
+ isHovering = true;
+ }
+
mCurrentTouch.pointerCount = 1;
- mCurrentTouch.pointers[0].id = 0;
- mCurrentTouch.pointers[0].x = mX;
- mCurrentTouch.pointers[0].y = mY;
- mCurrentTouch.pointers[0].pressure = mPressure;
- mCurrentTouch.pointers[0].touchMajor = 0;
- mCurrentTouch.pointers[0].touchMinor = 0;
- mCurrentTouch.pointers[0].toolMajor = mToolWidth;
- mCurrentTouch.pointers[0].toolMinor = mToolWidth;
- mCurrentTouch.pointers[0].orientation = 0;
- mCurrentTouch.pointers[0].distance = 0;
- mCurrentTouch.pointers[0].isStylus = false; // TODO: Set stylus
mCurrentTouch.idToIndex[0] = 0;
mCurrentTouch.idBits.markBit(0);
- mCurrentTouch.buttonState = mButtonState;
+ mCurrentTouch.buttonState = buttonState;
+
+ PointerData& outPointer = mCurrentTouch.pointers[0];
+ outPointer.id = 0;
+ outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX();
+ outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY();
+ outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();
+ outPointer.touchMajor = 0;
+ outPointer.touchMinor = 0;
+ outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
+ outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
+ outPointer.orientation = 0;
+ outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance();
+ outPointer.toolType = mTouchButtonAccumulator.getToolType();
+ if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+ outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+ }
+ outPointer.isHovering = isHovering;
}
syncTouch(when, true);
-
- mAccumulator.clear();
}
void SingleTouchInputMapper::configureRawAxes() {
TouchInputMapper::configureRawAxes();
+ mTouchButtonAccumulator.configure(getDevice());
+
getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mRawAxes.x);
getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mRawAxes.y);
getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mRawAxes.pressure);
getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mRawAxes.toolMajor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_DISTANCE, & mRawAxes.distance);
}
// --- MultiTouchInputMapper ---
MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) :
- TouchInputMapper(device), mSlotCount(0), mUsingSlotsProtocol(false) {
+ TouchInputMapper(device) {
}
MultiTouchInputMapper::~MultiTouchInputMapper() {
}
void MultiTouchInputMapper::clearState() {
- mAccumulator.clearSlots(mSlotCount);
- mAccumulator.clearButtons();
- mButtonState = 0;
+ mCursorButtonAccumulator.clearButtons();
+ mTouchButtonAccumulator.clearButtons();
mPointerIdBits.clear();
- if (mUsingSlotsProtocol) {
+ if (mMultiTouchMotionAccumulator.isUsingSlotsProtocol()) {
// Query the driver for the current slot index and use it as the initial slot
// before we start reading events from the device. It is possible that the
// current slot index will not be the same as it was when the first event was
@@ -4924,12 +5139,16 @@ void MultiTouchInputMapper::clearState() {
// two slots will be confused until the next ABS_MT_SLOT event is received.
// This can cause the touch point to "jump", but at least there will be
// no stuck touches.
+ int32_t initialSlot;
status_t status = getEventHub()->getAbsoluteAxisValue(getDeviceId(), ABS_MT_SLOT,
- &mAccumulator.currentSlot);
+ &initialSlot);
if (status) {
LOGW("Could not retrieve current multitouch slot index. status=%d", status);
- mAccumulator.currentSlot = -1;
+ initialSlot = -1;
}
+ mMultiTouchMotionAccumulator.clearSlots(initialSlot);
+ } else {
+ mMultiTouchMotionAccumulator.clearSlots(-1);
}
}
@@ -4940,124 +5159,26 @@ void MultiTouchInputMapper::reset() {
}
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
- switch (rawEvent->type) {
- case EV_KEY: {
- if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
- int32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode);
- if (buttonState) {
- if (rawEvent->value) {
- mAccumulator.buttonDown |= buttonState;
- } else {
- mAccumulator.buttonUp |= buttonState;
- }
- }
- }
- break;
- }
-
- case EV_ABS: {
- bool newSlot = false;
- if (mUsingSlotsProtocol && rawEvent->scanCode == ABS_MT_SLOT) {
- mAccumulator.currentSlot = rawEvent->value;
- newSlot = true;
- }
-
- if (mAccumulator.currentSlot < 0 || size_t(mAccumulator.currentSlot) >= mSlotCount) {
-#if DEBUG_POINTERS
- if (newSlot) {
- LOGW("MultiTouch device %s emitted invalid slot index %d but it "
- "should be between 0 and %d; ignoring this slot.",
- getDeviceName().string(), mAccumulator.currentSlot, mSlotCount);
- }
-#endif
- break;
- }
-
- Accumulator::Slot* slot = &mAccumulator.slots[mAccumulator.currentSlot];
-
- switch (rawEvent->scanCode) {
- case ABS_MT_POSITION_X:
- slot->fields |= Accumulator::FIELD_ABS_MT_POSITION_X;
- slot->absMTPositionX = rawEvent->value;
- break;
- case ABS_MT_POSITION_Y:
- slot->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y;
- slot->absMTPositionY = rawEvent->value;
- break;
- case ABS_MT_TOUCH_MAJOR:
- slot->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;
- slot->absMTTouchMajor = rawEvent->value;
- break;
- case ABS_MT_TOUCH_MINOR:
- slot->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR;
- slot->absMTTouchMinor = rawEvent->value;
- break;
- case ABS_MT_WIDTH_MAJOR:
- slot->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
- slot->absMTWidthMajor = rawEvent->value;
- break;
- case ABS_MT_WIDTH_MINOR:
- slot->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR;
- slot->absMTWidthMinor = rawEvent->value;
- break;
- case ABS_MT_ORIENTATION:
- slot->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION;
- slot->absMTOrientation = rawEvent->value;
- break;
- case ABS_MT_TRACKING_ID:
- if (mUsingSlotsProtocol && rawEvent->value < 0) {
- slot->clear();
- } else {
- slot->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID;
- slot->absMTTrackingId = rawEvent->value;
- }
- break;
- case ABS_MT_PRESSURE:
- slot->fields |= Accumulator::FIELD_ABS_MT_PRESSURE;
- slot->absMTPressure = rawEvent->value;
- break;
- case ABS_MT_TOOL_TYPE:
- slot->fields |= Accumulator::FIELD_ABS_MT_TOOL_TYPE;
- slot->absMTToolType = rawEvent->value;
- break;
- }
- break;
- }
+ mCursorButtonAccumulator.process(rawEvent);
+ mTouchButtonAccumulator.process(rawEvent);
+ mMultiTouchMotionAccumulator.process(rawEvent);
- case EV_SYN:
- switch (rawEvent->scanCode) {
- case SYN_MT_REPORT: {
- // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
- mAccumulator.currentSlot += 1;
- break;
- }
-
- case SYN_REPORT:
- sync(rawEvent->when);
- break;
- }
- break;
+ if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {
+ sync(rawEvent->when);
}
}
void MultiTouchInputMapper::sync(nsecs_t when) {
- static const uint32_t REQUIRED_FIELDS =
- Accumulator::FIELD_ABS_MT_POSITION_X | Accumulator::FIELD_ABS_MT_POSITION_Y;
-
- size_t inCount = mSlotCount;
+ size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
size_t outCount = 0;
bool havePointerIds = true;
mCurrentTouch.clear();
for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
- const Accumulator::Slot& inSlot = mAccumulator.slots[inIndex];
- uint32_t fields = inSlot.fields;
-
- if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
- // Some drivers send empty MT sync packets without X / Y to indicate a pointer up.
- // This may also indicate an unused slot.
- // Drop this finger.
+ const MultiTouchMotionAccumulator::Slot* inSlot =
+ mMultiTouchMotionAccumulator.getSlot(inIndex);
+ if (!inSlot->isInUse()) {
continue;
}
@@ -5071,76 +5192,32 @@ void MultiTouchInputMapper::sync(nsecs_t when) {
}
PointerData& outPointer = mCurrentTouch.pointers[outCount];
- outPointer.x = inSlot.absMTPositionX;
- outPointer.y = inSlot.absMTPositionY;
-
- if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) {
- outPointer.pressure = inSlot.absMTPressure;
- } else {
- // Default pressure to 0 if absent.
- outPointer.pressure = 0;
- }
-
- if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) {
- if (inSlot.absMTTouchMajor <= 0) {
- // Some devices send sync packets with X / Y but with a 0 touch major to indicate
- // a pointer going up. Drop this finger.
- continue;
+ outPointer.x = inSlot->getX();
+ outPointer.y = inSlot->getY();
+ outPointer.pressure = inSlot->getPressure();
+ outPointer.touchMajor = inSlot->getTouchMajor();
+ outPointer.touchMinor = inSlot->getTouchMinor();
+ outPointer.toolMajor = inSlot->getToolMajor();
+ outPointer.toolMinor = inSlot->getToolMinor();
+ outPointer.orientation = inSlot->getOrientation();
+ outPointer.distance = inSlot->getDistance();
+
+ outPointer.toolType = inSlot->getToolType();
+ if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+ outPointer.toolType = mTouchButtonAccumulator.getToolType();
+ if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+ outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
}
- outPointer.touchMajor = inSlot.absMTTouchMajor;
- } else {
- // Default touch area to 0 if absent.
- outPointer.touchMajor = 0;
}
- if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) {
- outPointer.touchMinor = inSlot.absMTTouchMinor;
- } else {
- // Assume touch area is circular.
- outPointer.touchMinor = outPointer.touchMajor;
- }
-
- if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) {
- outPointer.toolMajor = inSlot.absMTWidthMajor;
- } else {
- // Default tool area to 0 if absent.
- outPointer.toolMajor = 0;
- }
-
- if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) {
- outPointer.toolMinor = inSlot.absMTWidthMinor;
- } else {
- // Assume tool area is circular.
- outPointer.toolMinor = outPointer.toolMajor;
- }
-
- if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) {
- outPointer.orientation = inSlot.absMTOrientation;
- } else {
- // Default orientation to vertical if absent.
- outPointer.orientation = 0;
- }
-
- if (fields & Accumulator::FIELD_ABS_MT_DISTANCE) {
- outPointer.distance = inSlot.absMTDistance;
- } else {
- // Default distance is 0 (direct contact).
- outPointer.distance = 0;
- }
-
- if (fields & Accumulator::FIELD_ABS_MT_TOOL_TYPE) {
- outPointer.isStylus = (inSlot.absMTToolType == MT_TOOL_PEN);
- } else {
- // Assume this is not a stylus.
- outPointer.isStylus = false;
- }
+ outPointer.isHovering = mTouchButtonAccumulator.isHovering()
+ || inSlot->getDistance() > 0;
// Assign pointer id using tracking id if available.
if (havePointerIds) {
+ int32_t trackingId = inSlot->getTrackingId();
int32_t id = -1;
- if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) {
- int32_t trackingId = inSlot.absMTTrackingId;
-
+ if (trackingId >= 0) {
for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
uint32_t n = idBits.firstMarkedBit();
idBits.clearBit(n);
@@ -5170,23 +5247,22 @@ void MultiTouchInputMapper::sync(nsecs_t when) {
}
mCurrentTouch.pointerCount = outCount;
-
- mButtonState = (mButtonState | mAccumulator.buttonDown) & ~mAccumulator.buttonUp;
- mCurrentTouch.buttonState = mButtonState;
+ mCurrentTouch.buttonState = mTouchButtonAccumulator.getButtonState();
mPointerIdBits = mCurrentTouch.idBits;
syncTouch(when, havePointerIds);
- if (!mUsingSlotsProtocol) {
- mAccumulator.clearSlots(mSlotCount);
+ if (!mMultiTouchMotionAccumulator.isUsingSlotsProtocol()) {
+ mMultiTouchMotionAccumulator.clearSlots(-1);
}
- mAccumulator.clearButtons();
}
void MultiTouchInputMapper::configureRawAxes() {
TouchInputMapper::configureRawAxes();
+ mTouchButtonAccumulator.configure(getDevice());
+
getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, &mRawAxes.x);
getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, &mRawAxes.y);
getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, &mRawAxes.touchMajor);
@@ -5201,21 +5277,18 @@ void MultiTouchInputMapper::configureRawAxes() {
if (mRawAxes.trackingId.valid
&& mRawAxes.slot.valid && mRawAxes.slot.minValue == 0 && mRawAxes.slot.maxValue > 0) {
- mSlotCount = mRawAxes.slot.maxValue + 1;
- if (mSlotCount > MAX_SLOTS) {
+ size_t slotCount = mRawAxes.slot.maxValue + 1;
+ if (slotCount > MAX_SLOTS) {
LOGW("MultiTouch Device %s reported %d slots but the framework "
"only supports a maximum of %d slots at this time.",
- getDeviceName().string(), mSlotCount, MAX_SLOTS);
- mSlotCount = MAX_SLOTS;
+ getDeviceName().string(), slotCount, MAX_SLOTS);
+ slotCount = MAX_SLOTS;
}
- mUsingSlotsProtocol = true;
+ mMultiTouchMotionAccumulator.configure(slotCount, true /*usingSlotsProtocol*/);
} else {
- mSlotCount = MAX_POINTERS;
- mUsingSlotsProtocol = false;
+ mMultiTouchMotionAccumulator.configure(MAX_POINTERS, false /*usingSlotsProtocol*/);
}
- mAccumulator.allocateSlots(mSlotCount);
-
clearState();
}
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index b1fdcf2..ee6990b 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -180,9 +180,11 @@ public:
};
/* Gets information about the display with the specified id.
+ * If external is true, returns the size of the external mirrored
+ * counterpart of the specified display.
* Returns true if the display info is available, false otherwise.
*/
- virtual bool getDisplayInfo(int32_t displayId,
+ virtual bool getDisplayInfo(int32_t displayId, bool external,
int32_t* width, int32_t* height, int32_t* orientation) = 0;
/* Gets the input reader configuration. */
@@ -430,9 +432,8 @@ public:
void fadePointer();
- inline const PropertyMap& getConfiguration() {
- return mConfiguration;
- }
+ inline const PropertyMap& getConfiguration() { return mConfiguration; }
+ inline EventHubInterface* getEventHub() { return mContext->getEventHub(); }
private:
InputReaderContext* mContext;
@@ -452,6 +453,171 @@ private:
};
+/* Keeps track of the state of mouse or touch pad buttons. */
+class CursorButtonAccumulator {
+public:
+ CursorButtonAccumulator();
+
+ void clearButtons();
+ void process(const RawEvent* rawEvent);
+
+ uint32_t getButtonState() const;
+
+private:
+ bool mBtnLeft;
+ bool mBtnRight;
+ bool mBtnMiddle;
+ bool mBtnBack;
+ bool mBtnSide;
+ bool mBtnForward;
+ bool mBtnExtra;
+ bool mBtnTask;
+};
+
+
+/* Keeps track of cursor movements. */
+
+class CursorMotionAccumulator {
+public:
+ CursorMotionAccumulator();
+ void configure(InputDevice* device);
+
+ void clearRelativeAxes();
+ void process(const RawEvent* rawEvent);
+
+ inline bool haveRelativeVWheel() const { return mHaveRelWheel; }
+ inline bool haveRelativeHWheel() const { return mHaveRelHWheel; }
+
+ inline int32_t getRelativeX() const { return mRelX; }
+ inline int32_t getRelativeY() const { return mRelY; }
+ inline int32_t getRelativeVWheel() const { return mRelWheel; }
+ inline int32_t getRelativeHWheel() const { return mRelHWheel; }
+
+private:
+ bool mHaveRelWheel;
+ bool mHaveRelHWheel;
+
+ int32_t mRelX;
+ int32_t mRelY;
+ int32_t mRelWheel;
+ int32_t mRelHWheel;
+};
+
+
+/* Keeps track of the state of touch, stylus and tool buttons. */
+class TouchButtonAccumulator {
+public:
+ TouchButtonAccumulator();
+ void configure(InputDevice* device);
+
+ void clearButtons();
+ void process(const RawEvent* rawEvent);
+
+ uint32_t getButtonState() const;
+ int32_t getToolType() const;
+ bool isActive() const;
+ bool isHovering() const;
+
+private:
+ bool mHaveBtnTouch;
+
+ bool mBtnTouch;
+ bool mBtnStylus;
+ bool mBtnStylus2;
+ bool mBtnToolFinger;
+ bool mBtnToolPen;
+ bool mBtnToolRubber;
+};
+
+
+/* Keeps track of the state of single-touch protocol. */
+class SingleTouchMotionAccumulator {
+public:
+ SingleTouchMotionAccumulator();
+
+ void clearAbsoluteAxes();
+ void process(const RawEvent* rawEvent);
+
+ inline int32_t getAbsoluteX() const { return mAbsX; }
+ inline int32_t getAbsoluteY() const { return mAbsY; }
+ inline int32_t getAbsolutePressure() const { return mAbsPressure; }
+ inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; }
+ inline int32_t getAbsoluteDistance() const { return mAbsDistance; }
+
+private:
+ int32_t mAbsX;
+ int32_t mAbsY;
+ int32_t mAbsPressure;
+ int32_t mAbsToolWidth;
+ int32_t mAbsDistance;
+};
+
+
+/* Keeps track of the state of multi-touch protocol. */
+class MultiTouchMotionAccumulator {
+public:
+ class Slot {
+ public:
+ inline bool isInUse() const { return mInUse; }
+ inline int32_t getX() const { return mAbsMTPositionX; }
+ inline int32_t getY() const { return mAbsMTPositionY; }
+ inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; }
+ inline int32_t getTouchMinor() const {
+ return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; }
+ inline int32_t getToolMajor() const { return mAbsMTWidthMajor; }
+ inline int32_t getToolMinor() const {
+ return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; }
+ inline int32_t getOrientation() const { return mAbsMTOrientation; }
+ inline int32_t getTrackingId() const { return mAbsMTTrackingId; }
+ inline int32_t getPressure() const { return mAbsMTPressure; }
+ inline int32_t getDistance() const { return mAbsMTDistance; }
+ inline int32_t getToolType() const;
+
+ private:
+ friend class MultiTouchMotionAccumulator;
+
+ bool mInUse;
+ bool mHaveAbsMTTouchMinor;
+ bool mHaveAbsMTWidthMinor;
+ bool mHaveAbsMTToolType;
+
+ int32_t mAbsMTPositionX;
+ int32_t mAbsMTPositionY;
+ int32_t mAbsMTTouchMajor;
+ int32_t mAbsMTTouchMinor;
+ int32_t mAbsMTWidthMajor;
+ int32_t mAbsMTWidthMinor;
+ int32_t mAbsMTOrientation;
+ int32_t mAbsMTTrackingId;
+ int32_t mAbsMTPressure;
+ int32_t mAbsMTToolType;
+ int32_t mAbsMTDistance;
+
+ Slot();
+ void clearIfInUse();
+ void clear();
+ };
+
+ MultiTouchMotionAccumulator();
+ ~MultiTouchMotionAccumulator();
+
+ void configure(size_t slotCount, bool usingSlotsProtocol);
+ void process(const RawEvent* rawEvent);
+
+ void clearSlots(int32_t initialSlot);
+
+ inline bool isUsingSlotsProtocol() const { return mUsingSlotsProtocol; }
+ inline size_t getSlotCount() const { return mSlotCount; }
+ inline const Slot* getSlot(size_t index) const { return &mSlots[index]; }
+
+private:
+ int32_t mCurrentSlot;
+ Slot* mSlots;
+ size_t mSlotCount;
+ bool mUsingSlotsProtocol;
+};
+
+
/* An input mapper transforms raw input events into cooked event data.
* A single input device can have multiple associated input mappers in order to interpret
* different classes of events.
@@ -615,29 +781,8 @@ private:
bool orientationAware;
} mParameters;
- struct Accumulator {
- enum {
- FIELD_BUTTONS = 1,
- FIELD_REL_X = 2,
- FIELD_REL_Y = 4,
- FIELD_REL_WHEEL = 8,
- FIELD_REL_HWHEEL = 16,
- };
-
- uint32_t fields;
-
- uint32_t buttonDown;
- uint32_t buttonUp;
-
- int32_t relX;
- int32_t relY;
- int32_t relWheel;
- int32_t relHWheel;
-
- inline void clear() {
- fields = 0;
- }
- } mAccumulator;
+ CursorButtonAccumulator mCursorButtonAccumulator;
+ CursorMotionAccumulator mCursorMotionAccumulator;
int32_t mSource;
float mXScale;
@@ -645,8 +790,6 @@ private:
float mXPrecision;
float mYPrecision;
- bool mHaveVWheel;
- bool mHaveHWheel;
float mVWheelScale;
float mHWheelScale;
@@ -722,7 +865,8 @@ protected:
int32_t toolMinor;
int32_t orientation;
int32_t distance;
- bool isStylus;
+ int32_t toolType; // AMOTION_EVENT_TOOL_TYPE constant
+ bool isHovering;
inline bool operator== (const PointerData& other) const {
return id == other.id
@@ -734,7 +878,9 @@ protected:
&& toolMajor == other.toolMajor
&& toolMinor == other.toolMinor
&& orientation == other.orientation
- && distance == other.distance;
+ && distance == other.distance
+ && toolType == other.toolType
+ && isHovering == other.isHovering;
}
inline bool operator!= (const PointerData& other) const {
return !(*this == other);
@@ -800,6 +946,7 @@ protected:
DeviceType deviceType;
int32_t associatedDisplayId;
+ bool associatedDisplayIsExternal;
bool orientationAware;
enum GestureMode {
@@ -1201,7 +1348,6 @@ private:
void suppressSwipeOntoVirtualKeys(nsecs_t when);
- int32_t getTouchToolType(bool isStylus) const;
bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y);
@@ -1221,40 +1367,9 @@ protected:
virtual void configureRawAxes();
private:
- struct Accumulator {
- enum {
- FIELD_BTN_TOUCH = 1,
- FIELD_ABS_X = 2,
- FIELD_ABS_Y = 4,
- FIELD_ABS_PRESSURE = 8,
- FIELD_ABS_TOOL_WIDTH = 16,
- FIELD_BUTTONS = 32,
- };
-
- uint32_t fields;
-
- bool btnTouch;
- int32_t absX;
- int32_t absY;
- int32_t absPressure;
- int32_t absToolWidth;
-
- uint32_t buttonDown;
- uint32_t buttonUp;
-
- inline void clear() {
- fields = 0;
- buttonDown = 0;
- buttonUp = 0;
- }
- } mAccumulator;
-
- bool mDown;
- int32_t mX;
- int32_t mY;
- int32_t mPressure;
- int32_t mToolWidth;
- int32_t mButtonState;
+ CursorButtonAccumulator mCursorButtonAccumulator;
+ TouchButtonAccumulator mTouchButtonAccumulator;
+ SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
void clearState();
@@ -1274,83 +1389,9 @@ protected:
virtual void configureRawAxes();
private:
- struct Accumulator {
- enum {
- FIELD_ABS_MT_POSITION_X = 1 << 0,
- FIELD_ABS_MT_POSITION_Y = 1 << 1,
- FIELD_ABS_MT_TOUCH_MAJOR = 1 << 2,
- FIELD_ABS_MT_TOUCH_MINOR = 1 << 3,
- FIELD_ABS_MT_WIDTH_MAJOR = 1 << 4,
- FIELD_ABS_MT_WIDTH_MINOR = 1 << 5,
- FIELD_ABS_MT_ORIENTATION = 1 << 6,
- FIELD_ABS_MT_TRACKING_ID = 1 << 7,
- FIELD_ABS_MT_PRESSURE = 1 << 8,
- FIELD_ABS_MT_TOOL_TYPE = 1 << 9,
- FIELD_ABS_MT_DISTANCE = 1 << 10,
- };
-
- struct Slot {
- uint32_t fields; // 0 if slot is unused
-
- int32_t absMTPositionX;
- int32_t absMTPositionY;
- int32_t absMTTouchMajor;
- int32_t absMTTouchMinor;
- int32_t absMTWidthMajor;
- int32_t absMTWidthMinor;
- int32_t absMTOrientation;
- int32_t absMTTrackingId;
- int32_t absMTPressure;
- int32_t absMTToolType;
- int32_t absMTDistance;
-
- inline Slot() {
- clear();
- }
-
- inline void clear() {
- fields = 0;
- }
- };
-
- // Current slot index.
- int32_t currentSlot;
-
- // Array of slots.
- Slot* slots;
-
- // Bitfield of buttons that went down or up.
- uint32_t buttonDown;
- uint32_t buttonUp;
-
- Accumulator() : currentSlot(0), slots(NULL), buttonDown(0), buttonUp(0) {
- }
-
- ~Accumulator() {
- delete[] slots;
- }
-
- void allocateSlots(size_t slotCount) {
- slots = new Slot[slotCount];
- }
-
- void clearSlots(size_t slotCount) {
- for (size_t i = 0; i < slotCount; i++) {
- slots[i].clear();
- }
- currentSlot = 0;
- }
-
- void clearButtons() {
- buttonDown = 0;
- buttonUp = 0;
- }
- } mAccumulator;
-
- size_t mSlotCount;
- bool mUsingSlotsProtocol;
-
- int32_t mButtonState;
+ CursorButtonAccumulator mCursorButtonAccumulator;
+ TouchButtonAccumulator mTouchButtonAccumulator;
+ MultiTouchMotionAccumulator mMultiTouchMotionAccumulator;
// Specifies the pointer id bits that are in use, and their associated tracking id.
BitSet32 mPointerIdBits;
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 131894a..8533743 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -157,7 +157,7 @@ public:
}
private:
- virtual bool getDisplayInfo(int32_t displayId,
+ virtual bool getDisplayInfo(int32_t displayId, bool external /*currently ignored*/,
int32_t* width, int32_t* height, int32_t* orientation) {
ssize_t index = mDisplayInfos.indexOfKey(displayId);
if (index >= 0) {
@@ -707,6 +707,15 @@ private:
return result;
}
+ virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const {
+ Device* device = getDevice(deviceId);
+ if (device) {
+ ssize_t index = device->keys.indexOfKey(scanCode);
+ return index >= 0;
+ }
+ return false;
+ }
+
virtual bool hasLed(int32_t deviceId, int32_t led) const {
Device* device = getDevice(deviceId);
return device && device->leds.indexOfKey(led) >= 0;
@@ -2116,6 +2125,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat
// Button press.
// Mostly testing non x/y behavior here so we don't need to check again elsewhere.
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
ASSERT_EQ(DEVICE_ID, args.deviceId);
@@ -2137,6 +2147,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat
// Button release. Should have same down time.
process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0);
+ process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
ASSERT_EQ(DEVICE_ID, args.deviceId);
@@ -2190,6 +2201,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) {
// Button press without following sync.
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
@@ -2197,6 +2209,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) {
// Button release without following sync.
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
@@ -2233,6 +2246,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) {
// Release Button.
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
@@ -2248,10 +2262,12 @@ TEST_F(CursorInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeButto
// Button press.
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
// Button release.
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
// Reset. Should not synthesize button up since button is not pressed.
@@ -2269,6 +2285,7 @@ TEST_F(CursorInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp) {
// Button press.
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
// Reset. Should synthesize button up.
@@ -2445,6 +2462,7 @@ float TouchInputMapperTest::toDisplayY(int32_t rawY) {
class SingleTouchInputMapperTest : public TouchInputMapperTest {
protected:
+ void prepareButtons();
void prepareAxes(int axes);
void processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y);
@@ -2455,6 +2473,10 @@ protected:
void processSync(SingleTouchInputMapper* mapper);
};
+void SingleTouchInputMapperTest::prepareButtons() {
+ mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, AKEYCODE_UNKNOWN, 0);
+}
+
void SingleTouchInputMapperTest::prepareAxes(int axes) {
if (axes & POSITION) {
mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_X,
@@ -2504,6 +2526,7 @@ void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) {
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ prepareButtons();
prepareAxes(POSITION);
addMapperAndConfigure(mapper);
@@ -2514,6 +2537,7 @@ TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsA
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X);
mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y);
+ prepareButtons();
prepareAxes(POSITION);
addMapperAndConfigure(mapper);
@@ -2522,6 +2546,7 @@ TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsA
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ prepareButtons();
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchPad");
addMapperAndConfigure(mapper);
@@ -2531,6 +2556,7 @@ TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTo
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ prepareButtons();
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
addMapperAndConfigure(mapper);
@@ -2542,6 +2568,7 @@ TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2570,6 +2597,7 @@ TEST_F(SingleTouchInputMapperTest, GetScanCodeState) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2598,6 +2626,7 @@ TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2615,6 +2644,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_WhenVirtualKeysAreDown_SendsUp) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2649,6 +2679,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2676,6 +2707,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNor
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2726,6 +2758,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2847,6 +2880,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMoves
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2920,6 +2954,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -3009,6 +3044,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
prepareAxes(POSITION);
addConfigurationProperty("touch.orientationAware", "0");
addMapperAndConfigure(mapper);
@@ -3032,6 +3068,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotate
TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
prepareAxes(POSITION);
addMapperAndConfigure(mapper);
@@ -3094,6 +3131,7 @@ TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
prepareAxes(POSITION | PRESSURE | TOOL);
addMapperAndConfigure(mapper);
@@ -3815,6 +3853,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinear
FakeInputDispatcher::NotifyMotionArgs args;
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
+
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
args.action);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 0843948..9a9cc8f 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1995,7 +1995,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
} else {
try {
- mNetd.setDnsServersForInterface(Integer.toString(netType),
+ mNetd.setDnsServersForInterface(p.getInterfaceName(),
NetworkUtils.makeStrings(dnses));
} catch (Exception e) {
Slog.e(TAG, "exception setting dns servers: " + e);
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 17ad268..39d2b1c 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -125,10 +125,14 @@ class NetworkManagementService extends INetworkManagementService.Stub {
private Thread mThread;
private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
+ // TODO: replace with RemoteCallbackList
private ArrayList<INetworkManagementEventObserver> mObservers;
+ private Object mQuotaLock = new Object();
/** Set of interfaces with active quotas. */
- private HashSet<String> mInterfaceQuota = Sets.newHashSet();
+ private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet();
+ /** Set of interfaces with active alerts. */
+ private HashSet<String> mActiveAlertIfaces = Sets.newHashSet();
/** Set of UIDs with active reject rules. */
private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
@@ -1058,26 +1062,25 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}
@Override
- public void setInterfaceQuota(String iface, long quota) {
+ public void setInterfaceQuota(String iface, long quotaBytes) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
// silently discard when control disabled
// TODO: eventually migrate to be always enabled
if (!mBandwidthControlEnabled) return;
- synchronized (mInterfaceQuota) {
- if (mInterfaceQuota.contains(iface)) {
- // TODO: eventually consider throwing
- return;
+ synchronized (mQuotaLock) {
+ if (mActiveQuotaIfaces.contains(iface)) {
+ throw new IllegalStateException("iface " + iface + " already has quota");
}
final StringBuilder command = new StringBuilder();
- command.append("bandwidth setiquota ").append(iface).append(" ").append(quota);
+ command.append("bandwidth setiquota ").append(iface).append(" ").append(quotaBytes);
try {
- // TODO: add support for quota shared across interfaces
+ // TODO: support quota shared across interfaces
mConnector.doCommand(command.toString());
- mInterfaceQuota.add(iface);
+ mActiveQuotaIfaces.add(iface);
} catch (NativeDaemonConnectorException e) {
throw new IllegalStateException("Error communicating to native daemon", e);
}
@@ -1092,8 +1095,8 @@ class NetworkManagementService extends INetworkManagementService.Stub {
// TODO: eventually migrate to be always enabled
if (!mBandwidthControlEnabled) return;
- synchronized (mInterfaceQuota) {
- if (!mInterfaceQuota.contains(iface)) {
+ synchronized (mQuotaLock) {
+ if (!mActiveQuotaIfaces.contains(iface)) {
// TODO: eventually consider throwing
return;
}
@@ -1102,9 +1105,42 @@ class NetworkManagementService extends INetworkManagementService.Stub {
command.append("bandwidth removeiquota ").append(iface);
try {
- // TODO: add support for quota shared across interfaces
+ // TODO: support quota shared across interfaces
+ mConnector.doCommand(command.toString());
+ mActiveQuotaIfaces.remove(iface);
+ mActiveAlertIfaces.remove(iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
+ @Override
+ public void setInterfaceAlert(String iface, long alertBytes) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // silently discard when control disabled
+ // TODO: eventually migrate to be always enabled
+ if (!mBandwidthControlEnabled) return;
+
+ // quick sanity check
+ if (!mActiveQuotaIfaces.contains(iface)) {
+ throw new IllegalStateException("setting alert requires existing quota on iface");
+ }
+
+ synchronized (mQuotaLock) {
+ if (mActiveAlertIfaces.contains(iface)) {
+ throw new IllegalStateException("iface " + iface + " already has alert");
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth setinterfacealert ").append(iface).append(" ").append(
+ alertBytes);
+
+ try {
+ // TODO: support alert shared across interfaces
mConnector.doCommand(command.toString());
- mInterfaceQuota.remove(iface);
+ mActiveAlertIfaces.add(iface);
} catch (NativeDaemonConnectorException e) {
throw new IllegalStateException("Error communicating to native daemon", e);
}
@@ -1112,6 +1148,51 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}
@Override
+ public void removeInterfaceAlert(String iface) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // silently discard when control disabled
+ // TODO: eventually migrate to be always enabled
+ if (!mBandwidthControlEnabled) return;
+
+ synchronized (mQuotaLock) {
+ if (!mActiveAlertIfaces.contains(iface)) {
+ // TODO: eventually consider throwing
+ return;
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth removeinterfacealert ").append(iface);
+
+ try {
+ // TODO: support alert shared across interfaces
+ mConnector.doCommand(command.toString());
+ mActiveAlertIfaces.remove(iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
+ @Override
+ public void setGlobalAlert(long alertBytes) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // silently discard when control disabled
+ // TODO: eventually migrate to be always enabled
+ if (!mBandwidthControlEnabled) return;
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth setglobalalert ").append(alertBytes);
+
+ try {
+ mConnector.doCommand(command.toString());
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+
+ @Override
public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
@@ -1375,18 +1456,17 @@ class NetworkManagementService extends INetworkManagementService.Stub {
try {
String cmd = "resolver setifdns " + iface;
for (String s : servers) {
- if (s != null && !"0.0.0.0".equals(s) &&
- !"::".equals(s) && !"0:0:0:0:0:0:0:0".equals(s)) {
- cmd += " " + InetAddress.getByName(s).getHostAddress();
+ InetAddress a = NetworkUtils.numericToInetAddress(s);
+ if (a.isAnyLocalAddress() == false) {
+ cmd += " " + a.getHostAddress();
}
}
-
mConnector.doCommand(cmd);
- } catch (UnknownHostException e) {
- throw new IllegalStateException("failed to resolve dns address.", e);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException("Error setting dnsn for interface", e);
} catch (NativeDaemonConnectorException e) {
throw new IllegalStateException(
- "Error communicating with native deamon to set dns for interface", e);
+ "Error communicating with native daemon to set dns for interface", e);
}
}
@@ -1412,7 +1492,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
mConnector.doCommand(cmd);
} catch (NativeDaemonConnectorException e) {
throw new IllegalStateException(
- "Error communicating with native deamon to flush interface " + iface, e);
+ "Error communicating with native daemon to flush interface " + iface, e);
}
}
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 92647e6..d0f8843 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1205,6 +1205,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
| AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
| AccessibilityEvent.TYPE_VIEW_SCROLLED;
+ private static final int RETRIEVAL_ALLOWING_WINDOW_CHANGE_EVENT_TYPES =
+ AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
+ | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT;
+
private int mRetrievalAlowingWindowId;
private boolean canDispatchAccessibilityEvent(AccessibilityEvent event) {
@@ -1216,9 +1220,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
public void updateRetrievalAllowingWindowAndEventSourceLocked(AccessibilityEvent event) {
final int windowId = event.getWindowId();
final int eventType = event.getEventType();
- if ((eventType & RETRIEVAL_ALLOWING_EVENT_TYPES) != 0) {
+ if ((eventType & RETRIEVAL_ALLOWING_WINDOW_CHANGE_EVENT_TYPES) != 0) {
mRetrievalAlowingWindowId = windowId;
- } else {
+ }
+ if ((eventType & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) {
event.setSource(null);
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 3389f33..66f88fc 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1821,7 +1821,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// An application record is attached to a previous process,
// clean it up now.
if (DEBUG_PROCESSES) Slog.v(TAG, "App died: " + app);
- handleAppDiedLocked(app, true);
+ handleAppDiedLocked(app, true, true);
}
}
@@ -2658,8 +2658,8 @@ public final class ActivityManagerService extends ActivityManagerNative
* to the process.
*/
private final void handleAppDiedLocked(ProcessRecord app,
- boolean restarting) {
- cleanUpApplicationRecordLocked(app, restarting, -1);
+ boolean restarting, boolean allowRestart) {
+ cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
if (!restarting) {
mLruProcesses.remove(app);
}
@@ -2791,7 +2791,7 @@ public final class ActivityManagerService extends ActivityManagerNative
TAG, "Dying app: " + app + ", pid: " + pid
+ ", thread: " + thread.asBinder());
boolean doLowMem = app.instrumentationClass == null;
- handleAppDiedLocked(app, false);
+ handleAppDiedLocked(app, false, true);
if (doLowMem) {
// If there are no longer any background processes running,
@@ -3195,7 +3195,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
killPackageProcessesLocked(packageName, pkgUid,
- SECONDARY_SERVER_ADJ, false, true);
+ SECONDARY_SERVER_ADJ, false, true, true);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -3358,7 +3358,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private final boolean killPackageProcessesLocked(String packageName, int uid,
- int minOomAdj, boolean callerWillRestart, boolean doit) {
+ int minOomAdj, boolean callerWillRestart, boolean allowRestart, boolean doit) {
ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
// Remove all processes this package may have touched: all with the
@@ -3369,6 +3369,10 @@ public final class ActivityManagerService extends ActivityManagerNative
final int NA = apps.size();
for (int ia=0; ia<NA; ia++) {
ProcessRecord app = apps.valueAt(ia);
+ if (app.persistent) {
+ // we don't kill persistent processes
+ continue;
+ }
if (app.removed) {
if (doit) {
procs.add(app);
@@ -3389,7 +3393,7 @@ public final class ActivityManagerService extends ActivityManagerNative
int N = procs.size();
for (int i=0; i<N; i++) {
- removeProcessLocked(procs.get(i), callerWillRestart);
+ removeProcessLocked(procs.get(i), callerWillRestart, allowRestart);
}
return N > 0;
}
@@ -3419,11 +3423,12 @@ public final class ActivityManagerService extends ActivityManagerNative
}
boolean didSomething = killPackageProcessesLocked(name, uid, -100,
- callerWillRestart, doit);
+ callerWillRestart, false, doit);
for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r.packageName.equals(name)) {
+ if (r.packageName.equals(name)
+ && (r.app == null || !r.app.persistent)) {
if (!doit) {
return true;
}
@@ -3439,7 +3444,8 @@ public final class ActivityManagerService extends ActivityManagerNative
ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
for (ServiceRecord service : mServices.values()) {
- if (service.packageName.equals(name)) {
+ if (service.packageName.equals(name)
+ && (service.app == null || !service.app.persistent)) {
if (!doit) {
return true;
}
@@ -3471,7 +3477,8 @@ public final class ActivityManagerService extends ActivityManagerNative
return didSomething;
}
- private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
+ private final boolean removeProcessLocked(ProcessRecord app,
+ boolean callerWillRestart, boolean allowRestart) {
final String name = app.processName;
final int uid = app.info.uid;
if (DEBUG_PROCESSES) Slog.d(
@@ -3490,7 +3497,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mPidsSelfLocked.remove(pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
- handleAppDiedLocked(app, true);
+ handleAppDiedLocked(app, true, allowRestart);
mLruProcesses.remove(app);
Process.killProcess(pid);
@@ -3600,7 +3607,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// If this application record is still attached to a previous
// process, clean it up now.
if (app.thread != null) {
- handleAppDiedLocked(app, true);
+ handleAppDiedLocked(app, true, true);
}
// Tell the process all about itself.
@@ -3783,7 +3790,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (badApp) {
// todo: Also need to kill application to deal with all
// kinds of exceptions.
- handleAppDiedLocked(app, false);
+ handleAppDiedLocked(app, false, true);
return false;
}
@@ -6643,7 +6650,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
Slog.i(TAG, "Removing system update proc: " + proc);
- removeProcessLocked(proc, true);
+ removeProcessLocked(proc, true, false);
}
}
@@ -6826,10 +6833,6 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
if (!app.persistent) {
- // Don't let services in this process be restarted and potentially
- // annoy the user repeatedly. Unless it is persistent, since those
- // processes run critical code.
- killServicesLocked(app, false);
// We don't want to start this process again until the user
// explicitly does so... but for persistent process, we really
// need to keep it running. If a persistent process is actually
@@ -6840,7 +6843,10 @@ public final class ActivityManagerService extends ActivityManagerNative
app.bad = true;
mProcessCrashTimes.remove(app.info.processName, app.info.uid);
app.removed = true;
- removeProcessLocked(app, false);
+ // Don't let services in this process be restarted and potentially
+ // annoy the user repeatedly. Unless it is persistent, since those
+ // processes run critical code.
+ removeProcessLocked(app, false, false);
mMainStack.resumeTopActivityLocked(null);
return false;
}
@@ -9120,7 +9126,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Should the service remain running? Note that in the
// extreme case of so many attempts to deliver a command
- // that it failed, that we also will stop it here.
+ // that it failed we also will stop it here.
if (sr.startRequested && (sr.stopIfKilled || canceled)) {
if (sr.pendingStarts.size() == 0) {
sr.startRequested = false;
@@ -9189,7 +9195,7 @@ public final class ActivityManagerService extends ActivityManagerNative
* a process when running in single process mode.
*/
private final void cleanUpApplicationRecordLocked(ProcessRecord app,
- boolean restarting, int index) {
+ boolean restarting, boolean allowRestart, int index) {
if (index >= 0) {
mLruProcesses.remove(index);
}
@@ -9221,7 +9227,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.foregroundActivities = false;
app.hasShownUi = false;
- killServicesLocked(app, true);
+ killServicesLocked(app, allowRestart);
boolean restart = false;
@@ -9238,7 +9244,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// See if someone is waiting for this provider... in which
// case we don't remove it, but just let it restart.
int i = 0;
- if (!app.bad) {
+ if (!app.bad && allowRestart) {
for (; i<NL; i++) {
if (mLaunchingProviders.get(i) == cpr) {
restart = true;
@@ -9994,8 +10000,12 @@ public final class ActivityManagerService extends ActivityManagerNative
while (it.hasNext()) {
ArrayList<ConnectionRecord> c = it.next();
for (int i=0; i<c.size(); i++) {
+ ConnectionRecord cr = c.get(i);
+ // There is still a connection to the service that is
+ // being brought down. Mark it as dead.
+ cr.serviceDead = true;
try {
- c.get(i).conn.connected(r.name, null);
+ cr.conn.connected(r.name, null);
} catch (Exception e) {
Slog.w(TAG, "Failure disconnecting service " + r.name +
" to connection " + c.get(i).conn.asBinder() +
@@ -10526,26 +10536,28 @@ public final class ActivityManagerService extends ActivityManagerNative
b.intent.apps.remove(b.client);
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Disconnecting binding " + b.intent
- + ": shouldUnbind=" + b.intent.hasBound);
- if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
- && b.intent.hasBound) {
- try {
- bumpServiceExecutingLocked(s, "unbind");
- updateOomAdjLocked(s.app);
- b.intent.hasBound = false;
- // Assume the client doesn't want to know about a rebind;
- // we will deal with that later if it asks for one.
- b.intent.doRebind = false;
- s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
- } catch (Exception e) {
- Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
- serviceDoneExecutingLocked(s, true);
+ if (!c.serviceDead) {
+ if (DEBUG_SERVICE) Slog.v(TAG, "Disconnecting binding " + b.intent
+ + ": shouldUnbind=" + b.intent.hasBound);
+ if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
+ && b.intent.hasBound) {
+ try {
+ bumpServiceExecutingLocked(s, "unbind");
+ updateOomAdjLocked(s.app);
+ b.intent.hasBound = false;
+ // Assume the client doesn't want to know about a rebind;
+ // we will deal with that later if it asks for one.
+ b.intent.doRebind = false;
+ s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
+ serviceDoneExecutingLocked(s, true);
+ }
+ }
+
+ if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
+ bringDownServiceLocked(s, false);
}
- }
-
- if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
- bringDownServiceLocked(s, false);
}
}
@@ -12774,6 +12786,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
ProcessRecord client = cr.binding.client;
+ int clientAdj = adj;
int myHiddenAdj = hiddenAdj;
if (myHiddenAdj > client.hiddenAdj) {
if (client.hiddenAdj >= VISIBLE_APP_ADJ) {
@@ -12782,8 +12795,35 @@ public final class ActivityManagerService extends ActivityManagerNative
myHiddenAdj = VISIBLE_APP_ADJ;
}
}
- int clientAdj = computeOomAdjLocked(
+ clientAdj = computeOomAdjLocked(
client, myHiddenAdj, TOP_APP, true);
+ String adjType = null;
+ if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
+ // Not doing bind OOM management, so treat
+ // this guy more like a started service.
+ if (app.hasShownUi) {
+ // If this process has shown some UI, let it immediately
+ // go to the LRU list because it may be pretty heavy with
+ // UI stuff. We'll tag it with a label just to help
+ // debug and understand what is going on.
+ if (adj > clientAdj) {
+ adjType = "bound-bg-ui-services";
+ }
+ clientAdj = adj;
+ } else {
+ if (now >= (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
+ // This service has not seen activity within
+ // recent memory, so allow it to drop to the
+ // LRU list if there is no other reason to keep
+ // it around. We'll also tag it with a label just
+ // to help debug and undertand what is going on.
+ if (adj > clientAdj) {
+ adjType = "bound-bg-services";
+ }
+ clientAdj = adj;
+ }
+ }
+ }
if (adj > clientAdj) {
adj = clientAdj >= VISIBLE_APP_ADJ
? clientAdj : VISIBLE_APP_ADJ;
@@ -12793,7 +12833,10 @@ public final class ActivityManagerService extends ActivityManagerNative
if (client.keeping) {
app.keeping = true;
}
- app.adjType = "service";
+ adjType = "service";
+ }
+ if (adjType != null) {
+ app.adjType = adjType;
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE;
app.adjSource = cr.binding.client;
@@ -13413,7 +13456,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Ignore exceptions.
}
}
- cleanUpApplicationRecordLocked(app, false, -1);
+ cleanUpApplicationRecordLocked(app, false, true, -1);
mRemovedProcesses.remove(i);
if (app.persistent) {
diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java
index 22acda9..0106114 100644
--- a/services/java/com/android/server/am/ConnectionRecord.java
+++ b/services/java/com/android/server/am/ConnectionRecord.java
@@ -32,6 +32,7 @@ class ConnectionRecord {
final int clientLabel; // String resource labeling this client.
final PendingIntent clientIntent; // How to launch the client.
String stringName; // Caching of toString.
+ boolean serviceDead; // Well is it?
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "binding=" + binding);
@@ -61,6 +62,9 @@ class ConnectionRecord {
sb.append("ConnectionRecord{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(' ');
+ if (serviceDead) {
+ sb.append("DEAD ");
+ }
sb.append(binding.service.shortName);
sb.append(":@");
sb.append(Integer.toHexString(System.identityHashCode(conn.asBinder())));
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index a5a6d8e..ce45998 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -202,7 +202,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
sm.start();
}
} else {
- if (sm != null) {
+ if (isUsb(iface)) {
+ // ignore usb0 down after enabling RNDIS
+ // we will handle disconnect in interfaceRemoved instead
+ Log.d(TAG, "ignoring interface down for " + iface);
+ } else if (sm != null) {
sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
mIfaces.remove(iface);
}
@@ -237,6 +241,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
public void interfaceAdded(String iface) {
+ if (DEBUG) Log.d(TAG, "interfaceAdded " + iface);
boolean found = false;
boolean usb = false;
if (isWifi(iface)) {
@@ -268,6 +273,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
public void interfaceRemoved(String iface) {
+ if (DEBUG) Log.d(TAG, "interfaceRemoved " + iface);
synchronized (mIfaces) {
TetherInterfaceSM sm = mIfaces.get(iface);
if (sm == null) {
@@ -542,6 +548,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
public int setUsbTethering(boolean enable) {
+ if (DEBUG) Log.d(TAG, "setUsbTethering(" + enable + ")");
UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
synchronized (this) {
diff --git a/services/java/com/android/server/location/GeocoderProxy.java b/services/java/com/android/server/location/GeocoderProxy.java
index e3131fe..b38ea13 100644
--- a/services/java/com/android/server/location/GeocoderProxy.java
+++ b/services/java/com/android/server/location/GeocoderProxy.java
@@ -47,7 +47,9 @@ public class GeocoderProxy {
public GeocoderProxy(Context context, String serviceName) {
mContext = context;
mIntent = new Intent(serviceName);
- mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ mContext.bindService(mIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+ | Context.BIND_ALLOW_OOM_MANAGEMENT);
}
/**
@@ -58,7 +60,9 @@ public class GeocoderProxy {
synchronized (mMutex) {
mContext.unbindService(mServiceConnection);
mServiceConnection = new Connection();
- mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ mContext.bindService(mIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+ | Context.BIND_ALLOW_OOM_MANAGEMENT);
}
}
@@ -67,14 +71,12 @@ public class GeocoderProxy {
private IGeocodeProvider mProvider;
public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(TAG, "onServiceConnected " + className);
synchronized (this) {
mProvider = IGeocodeProvider.Stub.asInterface(service);
}
}
public void onServiceDisconnected(ComponentName className) {
- Log.d(TAG, "onServiceDisconnected " + className);
synchronized (this) {
mProvider = null;
}
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
index 1a1a170..0bc1664 100644
--- a/services/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -28,7 +28,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.WorkSource;
import android.util.Log;
@@ -65,7 +64,9 @@ public class LocationProviderProxy implements LocationProviderInterface {
mName = name;
mIntent = new Intent(serviceName);
mHandler = handler;
- mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ mContext.bindService(mIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+ | Context.BIND_ALLOW_OOM_MANAGEMENT);
}
/**
@@ -76,7 +77,9 @@ public class LocationProviderProxy implements LocationProviderInterface {
synchronized (mMutex) {
mContext.unbindService(mServiceConnection);
mServiceConnection = new Connection();
- mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ mContext.bindService(mIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+ | Context.BIND_ALLOW_OOM_MANAGEMENT);
}
}
@@ -88,7 +91,6 @@ public class LocationProviderProxy implements LocationProviderInterface {
private DummyLocationProvider mCachedAttributes; // synchronized by mMutex
public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(TAG, "LocationProviderProxy.onServiceConnected " + className);
synchronized (this) {
mProvider = ILocationProvider.Stub.asInterface(service);
if (mProvider != null) {
@@ -98,7 +100,6 @@ public class LocationProviderProxy implements LocationProviderInterface {
}
public void onServiceDisconnected(ComponentName className) {
- Log.d(TAG, "LocationProviderProxy.onServiceDisconnected " + className);
synchronized (this) {
mProvider = null;
}
diff --git a/services/java/com/android/server/net/NetworkAlertObserver.java b/services/java/com/android/server/net/NetworkAlertObserver.java
new file mode 100644
index 0000000..0d1c3b2
--- /dev/null
+++ b/services/java/com/android/server/net/NetworkAlertObserver.java
@@ -0,0 +1,44 @@
+/*
+ * 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.server.net;
+
+import android.net.INetworkManagementEventObserver;
+
+/**
+ * @hide
+ */
+public abstract class NetworkAlertObserver extends INetworkManagementEventObserver.Stub {
+ @Override
+ public void interfaceStatusChanged(String iface, boolean up) {
+ // ignored; interface changes come through ConnectivityService
+ }
+
+ @Override
+ public void interfaceRemoved(String iface) {
+ // ignored; interface changes come through ConnectivityService
+ }
+
+ @Override
+ public void interfaceLinkStateChanged(String iface, boolean up) {
+ // ignored; interface changes come through ConnectivityService
+ }
+
+ @Override
+ public void interfaceAdded(String iface) {
+ // ignored; interface changes come through ConnectivityService
+ }
+}
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 435c394..2e1e69b 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -29,9 +29,8 @@ import static android.net.ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHA
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
+import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
-import static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_LIMIT;
-import static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_WARNING;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -56,6 +55,7 @@ import android.app.IProcessObserver;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -64,6 +64,7 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
+import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
@@ -131,14 +132,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final boolean LOGD = true;
private static final boolean LOGV = false;
- private static final int VERSION_CURRENT = 1;
+ private static final int VERSION_INIT = 1;
+ private static final int VERSION_ADDED_SNOOZE = 2;
private static final long KB_IN_BYTES = 1024;
private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
- private static final int TYPE_WARNING = 0x1;
- private static final int TYPE_LIMIT = 0x2;
+ // @VisibleForTesting
+ public static final int TYPE_WARNING = 0x1;
+ public static final int TYPE_LIMIT = 0x2;
+ public static final int TYPE_LIMIT_SNOOZED = 0x3;
private static final String TAG_POLICY_LIST = "policy-list";
private static final String TAG_NETWORK_POLICY = "network-policy";
@@ -150,6 +154,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final String ATTR_CYCLE_DAY = "cycleDay";
private static final String ATTR_WARNING_BYTES = "warningBytes";
private static final String ATTR_LIMIT_BYTES = "limitBytes";
+ private static final String ATTR_LAST_SNOOZE = "lastSnooze";
private static final String ATTR_UID = "uid";
private static final String ATTR_POLICY = "policy";
@@ -162,7 +167,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final IActivityManager mActivityManager;
private final IPowerManager mPowerManager;
private final INetworkStatsService mNetworkStats;
- private final INetworkManagementService mNetworkManagement;
+ private final INetworkManagementService mNetworkManager;
private final TrustedTime mTime;
private IConnectivityManager mConnManager;
@@ -173,18 +178,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private boolean mScreenOn;
private boolean mBackgroundData;
- /** Current policy for network templates. */
- private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
- /** Current derived network rules for ifaces. */
+ /** Defined network policies. */
+ private HashMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = Maps.newHashMap();
+ /** Currently active network rules for ifaces. */
private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
- /** Current policy for each UID. */
+ /** Defined UID policies. */
private SparseIntArray mUidPolicy = new SparseIntArray();
- /** Current derived rules for each UID. */
+ /** Currently derived rules for each UID. */
private SparseIntArray mUidRules = new SparseIntArray();
/** Set of ifaces that are metered. */
private HashSet<String> mMeteredIfaces = Sets.newHashSet();
+ /** Set of over-limit templates that have been notified. */
+ private HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet();
/** Foreground at both UID and PID granularity. */
private SparseBooleanArray mUidForeground = new SparseBooleanArray();
@@ -202,6 +209,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
+ // TODO: migrate notifications to SystemUI
+
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
IPowerManager powerManager, INetworkStatsService networkStats,
INetworkManagementService networkManagement) {
@@ -221,7 +230,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mActivityManager = checkNotNull(activityManager, "missing activityManager");
mPowerManager = checkNotNull(powerManager, "missing powerManager");
mNetworkStats = checkNotNull(networkStats, "missing networkStats");
- mNetworkManagement = checkNotNull(networkManagement, "missing networkManagement");
+ mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
mTime = checkNotNull(time, "missing TrustedTime");
mHandlerThread = new HandlerThread(TAG);
@@ -256,13 +265,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
Slog.e(TAG, "unable to register IProcessObserver", e);
}
+ try {
+ mNetworkManager.registerObserver(mAlertObserver);
+ } catch (RemoteException e) {
+ // ouch, no alert updates means we fall back to
+ // ACTION_NETWORK_STATS_UPDATED broadcasts.
+ Slog.e(TAG, "unable to register INetworkManagementEventObserver", e);
+ }
+
// TODO: traverse existing processes to know foreground state, or have
// activitymanager dispatch current state when new observer attached.
final IntentFilter screenFilter = new IntentFilter();
screenFilter.addAction(Intent.ACTION_SCREEN_ON);
screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
- mContext.registerReceiver(mScreenReceiver, screenFilter);
+ mContext.registerReceiver(mScreenReceiver, screenFilter, null, mHandler);
// watch for network interfaces to be claimed
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
@@ -272,7 +289,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(ACTION_PACKAGE_ADDED);
packageFilter.addAction(ACTION_UID_REMOVED);
- packageFilter.addDataScheme("package");
mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
// listen for stats update events
@@ -393,6 +409,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
};
/**
+ * Observer that watches for {@link INetworkManagementService} alerts.
+ */
+ private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() {
+ @Override
+ public void limitReached(String limitName, String iface) {
+ // only someone like NMS should be calling us
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ synchronized (mRulesLock) {
+ if (mMeteredIfaces.contains(iface)) {
+ try {
+ // force stats update to make sure we have numbers that
+ // caused alert to trigger.
+ mNetworkStats.forceUpdate();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "problem updating network stats");
+ }
+
+ updateNotificationsLocked();
+ }
+ }
+ }
+ };
+
+ /**
* Check {@link NetworkPolicy} against current {@link INetworkStatsService}
* to show visible notifications as needed.
*/
@@ -415,42 +456,69 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
- final long total;
+ final long totalBytes;
try {
final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
policy.template, start, end);
final NetworkStats.Entry entry = stats.getValues(0, null);
- total = entry.rxBytes + entry.txBytes;
+ totalBytes = entry.rxBytes + entry.txBytes;
} catch (RemoteException e) {
Slog.w(TAG, "problem reading summary for template " + policy.template);
continue;
}
- if (policy.limitBytes != LIMIT_DISABLED && total >= policy.limitBytes) {
+ if (policy.limitBytes != LIMIT_DISABLED && totalBytes >= policy.limitBytes) {
cancelNotification(policy, TYPE_WARNING);
- enqueueNotification(policy, TYPE_LIMIT);
+
+ if (policy.lastSnooze >= start) {
+ cancelNotification(policy, TYPE_LIMIT);
+ enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
+ } else {
+ cancelNotification(policy, TYPE_LIMIT_SNOOZED);
+ enqueueNotification(policy, TYPE_LIMIT, totalBytes);
+ notifyOverLimitLocked(policy.template);
+ }
+
} else {
cancelNotification(policy, TYPE_LIMIT);
+ cancelNotification(policy, TYPE_LIMIT_SNOOZED);
+ notifyUnderLimitLocked(policy.template);
- if (policy.warningBytes != WARNING_DISABLED && total >= policy.warningBytes) {
- enqueueNotification(policy, TYPE_WARNING);
+ if (policy.warningBytes != WARNING_DISABLED && totalBytes >= policy.warningBytes) {
+ enqueueNotification(policy, TYPE_WARNING, totalBytes);
} else {
cancelNotification(policy, TYPE_WARNING);
}
}
-
}
// clear notifications for non-active policies
- for (NetworkPolicy policy : mNetworkPolicy) {
+ for (NetworkPolicy policy : mNetworkPolicy.values()) {
if (!mNetworkRules.containsKey(policy)) {
cancelNotification(policy, TYPE_WARNING);
cancelNotification(policy, TYPE_LIMIT);
+ cancelNotification(policy, TYPE_LIMIT_SNOOZED);
+ notifyUnderLimitLocked(policy.template);
}
}
}
/**
+ * Notify that given {@link NetworkTemplate} is over
+ * {@link NetworkPolicy#limitBytes}, potentially showing dialog to user.
+ */
+ private void notifyOverLimitLocked(NetworkTemplate template) {
+ if (!mOverLimitNotified.contains(template)) {
+ mContext.startActivity(buildNetworkOverLimitIntent(template));
+ mOverLimitNotified.add(template);
+ }
+ }
+
+ private void notifyUnderLimitLocked(NetworkTemplate template) {
+ mOverLimitNotified.remove(template);
+ }
+
+ /**
* Build unique tag that identifies an active {@link NetworkPolicy}
* notification of a specific type, like {@link #TYPE_LIMIT}.
*/
@@ -462,7 +530,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* Show notification for combined {@link NetworkPolicy} and specific type,
* like {@link #TYPE_LIMIT}. Okay to call multiple times.
*/
- private void enqueueNotification(NetworkPolicy policy, int type) {
+ private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
final String tag = buildNotificationTag(policy, type);
final Notification.Builder builder = new Notification.Builder(mContext);
builder.setOnlyAlertOnce(true);
@@ -471,8 +539,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final Resources res = mContext.getResources();
switch (type) {
case TYPE_WARNING: {
- final String title = res.getString(R.string.data_usage_warning_title);
- final String body = res.getString(R.string.data_usage_warning_body,
+ final CharSequence title = res.getText(R.string.data_usage_warning_title);
+ final CharSequence body = res.getString(R.string.data_usage_warning_body,
Formatter.formatFileSize(mContext, policy.warningBytes));
builder.setSmallIcon(R.drawable.ic_menu_info_details);
@@ -480,25 +548,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
builder.setContentTitle(title);
builder.setContentText(body);
- final Intent intent = new Intent(ACTION_DATA_USAGE_WARNING);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule());
+ final Intent intent = buildViewDataUsageIntent(policy.template);
builder.setContentIntent(PendingIntent.getActivity(
mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
break;
}
case TYPE_LIMIT: {
- final String title;
- final String body = res.getString(R.string.data_usage_limit_body);
+ final CharSequence body = res.getText(R.string.data_usage_limit_body);
+
+ final CharSequence title;
switch (policy.template.getMatchRule()) {
case MATCH_MOBILE_3G_LOWER:
- title = res.getString(R.string.data_usage_3g_limit_title);
+ title = res.getText(R.string.data_usage_3g_limit_title);
break;
case MATCH_MOBILE_4G:
- title = res.getString(R.string.data_usage_4g_limit_title);
+ title = res.getText(R.string.data_usage_4g_limit_title);
break;
default:
- title = res.getString(R.string.data_usage_mobile_limit_title);
+ title = res.getText(R.string.data_usage_mobile_limit_title);
break;
}
@@ -507,9 +574,35 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
builder.setContentTitle(title);
builder.setContentText(body);
- final Intent intent = new Intent(ACTION_DATA_USAGE_LIMIT);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule());
+ final Intent intent = buildNetworkOverLimitIntent(policy.template);
+ builder.setContentIntent(PendingIntent.getActivity(
+ mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ }
+ case TYPE_LIMIT_SNOOZED: {
+ final long overBytes = totalBytes - policy.limitBytes;
+ final CharSequence body = res.getString(R.string.data_usage_limit_snoozed_body,
+ Formatter.formatFileSize(mContext, overBytes));
+
+ final CharSequence title;
+ switch (policy.template.getMatchRule()) {
+ case MATCH_MOBILE_3G_LOWER:
+ title = res.getText(R.string.data_usage_3g_limit_snoozed_title);
+ break;
+ case MATCH_MOBILE_4G:
+ title = res.getText(R.string.data_usage_4g_limit_snoozed_title);
+ break;
+ default:
+ title = res.getText(R.string.data_usage_mobile_limit_snoozed_title);
+ break;
+ }
+
+ builder.setSmallIcon(R.drawable.ic_menu_info_details);
+ builder.setTicker(title);
+ builder.setContentTitle(title);
+ builder.setContentText(body);
+
+ final Intent intent = buildViewDataUsageIntent(policy.template);
builder.setContentIntent(PendingIntent.getActivity(
mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
break;
@@ -591,7 +684,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// build list of rules and ifaces to enforce them against
mNetworkRules.clear();
final ArrayList<String> ifaceList = Lists.newArrayList();
- for (NetworkPolicy policy : mNetworkPolicy) {
+ for (NetworkPolicy policy : mNetworkPolicy.values()) {
// collect all active ifaces that match this template
ifaceList.clear();
@@ -642,11 +735,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+ Arrays.toString(ifaces));
}
- // TODO: register for warning notification trigger through NMS
+ final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
+ final boolean hasWarning = policy.warningBytes != WARNING_DISABLED;
- if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
- // remaining "quota" is based on usage in current cycle
- final long quota = Math.max(0, policy.limitBytes - total);
+ if (hasLimit || hasWarning) {
+ final long quotaBytes;
+ if (hasLimit) {
+ // remaining "quota" is based on usage in current cycle
+ quotaBytes = Math.max(0, policy.limitBytes - total);
+ } else {
+ // to track warning alert later, use a high quota
+ quotaBytes = Long.MAX_VALUE;
+ }
if (ifaces.length > 1) {
// TODO: switch to shared quota once NMS supports
@@ -655,8 +755,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
for (String iface : ifaces) {
removeInterfaceQuota(iface);
- setInterfaceQuota(iface, quota);
- newMeteredIfaces.add(iface);
+ if (quotaBytes > 0) {
+ setInterfaceQuota(iface, quotaBytes);
+ newMeteredIfaces.add(iface);
+ }
+ }
+ }
+
+ if (hasWarning) {
+ final long alertBytes = Math.max(0, policy.warningBytes - total);
+ for (String iface : ifaces) {
+ removeInterfaceAlert(iface);
+ if (alertBytes > 0) {
+ setInterfaceAlert(iface, alertBytes);
+ }
}
}
}
@@ -685,7 +797,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// examine to see if any policy is defined for active mobile
boolean mobileDefined = false;
- for (NetworkPolicy policy : mNetworkPolicy) {
+ for (NetworkPolicy policy : mNetworkPolicy.values()) {
if (policy.template.matches(probeIdent)) {
mobileDefined = true;
}
@@ -704,7 +816,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final int cycleDay = time.monthDay;
final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
- mNetworkPolicy.add(new NetworkPolicy(template, cycleDay, warningBytes, LIMIT_DISABLED));
+ mNetworkPolicy.put(template, new NetworkPolicy(
+ template, cycleDay, warningBytes, LIMIT_DISABLED, SNOOZE_NEVER));
writePolicyLocked();
}
}
@@ -723,7 +836,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
in.setInput(fis, null);
int type;
- int version = VERSION_CURRENT;
+ int version = VERSION_INIT;
while ((type = in.next()) != END_DOCUMENT) {
final String tag = in.getName();
if (type == START_TAG) {
@@ -736,11 +849,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
+ final long lastSnooze;
+ if (version >= VERSION_ADDED_SNOOZE) {
+ lastSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
+ } else {
+ lastSnooze = SNOOZE_NEVER;
+ }
final NetworkTemplate template = new NetworkTemplate(
networkTemplate, subscriberId);
- mNetworkPolicy.add(
- new NetworkPolicy(template, cycleDay, warningBytes, limitBytes));
+ mNetworkPolicy.put(template, new NetworkPolicy(
+ template, cycleDay, warningBytes, limitBytes, lastSnooze));
} else if (TAG_UID_POLICY.equals(tag)) {
final int uid = readIntAttribute(in, ATTR_UID);
@@ -778,10 +897,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
out.startDocument(null, true);
out.startTag(null, TAG_POLICY_LIST);
- writeIntAttribute(out, ATTR_VERSION, VERSION_CURRENT);
+ writeIntAttribute(out, ATTR_VERSION, VERSION_ADDED_SNOOZE);
// write all known network policies
- for (NetworkPolicy policy : mNetworkPolicy) {
+ for (NetworkPolicy policy : mNetworkPolicy.values()) {
final NetworkTemplate template = policy.template;
out.startTag(null, TAG_NETWORK_POLICY);
@@ -793,6 +912,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
+ writeLongAttribute(out, ATTR_LAST_SNOOZE, policy.lastSnooze);
out.endTag(null, TAG_NETWORK_POLICY);
}
@@ -880,7 +1000,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
synchronized (mRulesLock) {
mNetworkPolicy.clear();
for (NetworkPolicy policy : policies) {
- mNetworkPolicy.add(policy);
+ mNetworkPolicy.put(policy.template, policy);
}
updateNetworkRulesLocked();
@@ -895,7 +1015,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
synchronized (mRulesLock) {
- return mNetworkPolicy.toArray(new NetworkPolicy[mNetworkPolicy.size()]);
+ return mNetworkPolicy.values().toArray(new NetworkPolicy[mNetworkPolicy.size()]);
+ }
+ }
+
+ @Override
+ public void snoozePolicy(NetworkTemplate template) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // try refreshing time source when stale
+ if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
+ mTime.forceRefresh();
+ }
+
+ final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
+ : System.currentTimeMillis();
+
+ synchronized (mRulesLock) {
+ // find and snooze local policy that matches
+ final NetworkPolicy policy = mNetworkPolicy.get(template);
+ if (policy == null) {
+ throw new IllegalArgumentException("unable to find policy for " + template);
+ }
+
+ policy.lastSnooze = currentTime;
+
+ updateNetworkRulesLocked();
+ updateNotificationsLocked();
+ writePolicyLocked();
}
}
@@ -903,9 +1050,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
+ final HashSet<String> argSet = new HashSet<String>();
+ for (String arg : args) {
+ argSet.add(arg);
+ }
+
synchronized (mRulesLock) {
+ if (argSet.contains("unsnooze")) {
+ for (NetworkPolicy policy : mNetworkPolicy.values()) {
+ policy.lastSnooze = SNOOZE_NEVER;
+ }
+ writePolicyLocked();
+ fout.println("Wiped snooze timestamps");
+ return;
+ }
+
fout.println("Network policies:");
- for (NetworkPolicy policy : mNetworkPolicy) {
+ for (NetworkPolicy policy : mNetworkPolicy.values()) {
fout.print(" "); fout.println(policy.toString());
}
@@ -1124,9 +1285,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
};
- private void setInterfaceQuota(String iface, long quota) {
+ private void setInterfaceQuota(String iface, long quotaBytes) {
try {
- mNetworkManagement.setInterfaceQuota(iface, quota);
+ mNetworkManager.setInterfaceQuota(iface, quotaBytes);
} catch (IllegalStateException e) {
Slog.e(TAG, "problem setting interface quota", e);
} catch (RemoteException e) {
@@ -1136,7 +1297,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private void removeInterfaceQuota(String iface) {
try {
- mNetworkManagement.removeInterfaceQuota(iface);
+ mNetworkManager.removeInterfaceQuota(iface);
} catch (IllegalStateException e) {
Slog.e(TAG, "problem removing interface quota", e);
} catch (RemoteException e) {
@@ -1144,9 +1305,29 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void setInterfaceAlert(String iface, long alertBytes) {
+ try {
+ mNetworkManager.setInterfaceAlert(iface, alertBytes);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem setting interface alert", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem setting interface alert", e);
+ }
+ }
+
+ private void removeInterfaceAlert(String iface) {
+ try {
+ mNetworkManager.removeInterfaceAlert(iface);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem removing interface alert", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem removing interface alert", e);
+ }
+ }
+
private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
try {
- mNetworkManagement.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+ mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
} catch (IllegalStateException e) {
Slog.e(TAG, "problem setting uid rules", e);
} catch (RemoteException e) {
@@ -1160,6 +1341,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return telephony.getSubscriberId();
}
+ private static Intent buildNetworkOverLimitIntent(NetworkTemplate template) {
+ final Intent intent = new Intent();
+ intent.setComponent(new ComponentName(
+ "com.android.systemui", "com.android.systemui.net.NetworkOverLimitActivity"));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
+ return intent;
+ }
+
+ private static Intent buildViewDataUsageIntent(NetworkTemplate template) {
+ final Intent intent = new Intent();
+ intent.setComponent(new ComponentName(
+ "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
+ return intent;
+ }
+
private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
final int size = source.size();
for (int i = 0; i < size; i++) {
@@ -1198,7 +1397,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
- throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
+ throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
}
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 9eb1179..88e0fa8 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static libcore.io.OsConstants.S_ISLNK;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
@@ -76,6 +77,7 @@ import android.os.Environment;
import android.os.FileObserver;
import android.os.FileUtils;
import android.os.FileUtils.FileStatus;
+import android.os.Debug;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -128,6 +130,9 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+
/**
* Keep track of all those .apks everywhere.
*
@@ -3338,16 +3343,27 @@ public class PackageManagerService extends IPackageManager.Stub {
} else if (nativeLibraryDir.getCanonicalFile().getParent()
.equals(dataPathString)) {
/*
+ * Make sure the native library dir isn't a symlink to
+ * something. If it is, ask installd to remove it and create
+ * a directory so we can copy to it afterwards.
+ */
+ boolean isSymLink;
+ try {
+ isSymLink = S_ISLNK(Libcore.os.lstat(nativeLibraryDir.getPath()).st_mode);
+ } catch (ErrnoException e) {
+ // This shouldn't happen, but we'll fail-safe.
+ isSymLink = true;
+ }
+ if (isSymLink) {
+ mInstaller.unlinkNativeLibraryDirectory(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.
+ * the libraries if necessary.
*/
- Slog.i(TAG, "Unpacking native libraries for " + path);
- mInstaller.unlinkNativeLibraryDirectory(dataPathString);
- NativeLibraryHelper.copyNativeBinariesLI(scanFile, nativeLibraryDir);
+ NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir);
} else {
Slog.i(TAG, "Linking native library dir for " + path);
mInstaller.linkNativeLibraryDirectory(dataPathString,
@@ -7930,7 +7946,7 @@ public class PackageManagerService extends IPackageManager.Stub {
.unlinkNativeLibraryDirectory(pkg.applicationInfo.dataDir) < 0) {
returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
} else {
- NativeLibraryHelper.copyNativeBinariesLI(new File(
+ NativeLibraryHelper.copyNativeBinariesIfNeededLI(new File(
newCodePath), new File(newNativePath));
}
} else {
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index f183f83..11cb555 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -528,10 +528,10 @@ public class UsbDeviceManager {
private void updateUsbNotification() {
if (mNotificationManager == null || !mUseUsbNotification) return;
+ int id = NOTIFICATION_NONE;
+ Resources r = mContext.getResources();
+ CharSequence title = null;
if (mConnected) {
- Resources r = mContext.getResources();
- CharSequence title = null;
- int id = NOTIFICATION_NONE;
if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
title = r.getText(
com.android.internal.R.string.usb_mtp_notification_title);
@@ -550,16 +550,19 @@ public class UsbDeviceManager {
com.android.internal.R.string.usb_accessory_notification_title);
id = NOTIFICATION_ACCESSORY;
} else {
- Slog.e(TAG, "No known USB function in updateUsbNotification");
- }
- if (id != mUsbNotificationId) {
- // clear notification if title needs changing
- if (mUsbNotificationId != NOTIFICATION_NONE) {
- mNotificationManager.cancel(mUsbNotificationId);
- mUsbNotificationId = NOTIFICATION_NONE;
+ // There is a different notification for USB tethering so we don't need one here
+ if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) {
+ Slog.e(TAG, "No known USB function in updateUsbNotification");
}
}
- if (mUsbNotificationId == NOTIFICATION_NONE) {
+ }
+ if (id != mUsbNotificationId) {
+ // clear notification if title needs changing
+ if (mUsbNotificationId != NOTIFICATION_NONE) {
+ mNotificationManager.cancel(mUsbNotificationId);
+ mUsbNotificationId = NOTIFICATION_NONE;
+ }
+ if (id != NOTIFICATION_NONE) {
CharSequence message = r.getText(
com.android.internal.R.string.usb_notification_message);
@@ -584,10 +587,6 @@ public class UsbDeviceManager {
mNotificationManager.notify(id, notification);
mUsbNotificationId = id;
}
-
- } else if (mUsbNotificationId != NOTIFICATION_NONE) {
- mNotificationManager.cancel(mUsbNotificationId);
- mUsbNotificationId = NOTIFICATION_NONE;
}
}
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index 8146fca..b37d1c2 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -123,8 +123,8 @@ class DragState {
// The drag window covers the entire display
mDragWindowHandle.frameLeft = 0;
mDragWindowHandle.frameTop = 0;
- mDragWindowHandle.frameRight = mService.mDisplay.getRealWidth();
- mDragWindowHandle.frameBottom = mService.mDisplay.getRealHeight();
+ mDragWindowHandle.frameRight = mService.mCurDisplayWidth;
+ mDragWindowHandle.frameBottom = mService.mCurDisplayHeight;
}
}
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index 3133a19..1d0857b 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -64,7 +64,8 @@ public class InputManager {
private static native void nativeInit(Context context,
Callbacks callbacks, MessageQueue messageQueue);
private static native void nativeStart();
- private static native void nativeSetDisplaySize(int displayId, int width, int height);
+ private static native void nativeSetDisplaySize(int displayId, int width, int height,
+ int externalWidth, int externalHeight);
private static native void nativeSetDisplayOrientation(int displayId, int rotation);
private static native int nativeGetScanCodeState(int deviceId, int sourceMask,
@@ -144,15 +145,17 @@ public class InputManager {
updatePointerSpeedFromSettings();
}
- public void setDisplaySize(int displayId, int width, int height) {
- if (width <= 0 || height <= 0) {
+ public void setDisplaySize(int displayId, int width, int height,
+ int externalWidth, int externalHeight) {
+ if (width <= 0 || height <= 0 || externalWidth <= 0 || externalHeight <= 0) {
throw new IllegalArgumentException("Invalid display id or dimensions.");
}
if (DEBUG) {
- Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height);
+ Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height
+ + " external size " + externalWidth + "x" + externalHeight);
}
- nativeSetDisplaySize(displayId, width, height);
+ nativeSetDisplaySize(displayId, width, height, externalWidth, externalHeight);
}
public void setDisplayOrientation(int displayId, int rotation) {
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 8470918..16af151 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -25,9 +25,7 @@ import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import android.util.DisplayMetrics;
import android.util.Slog;
-import android.view.Display;
import android.view.Surface;
import android.view.SurfaceSession;
import android.view.animation.Animation;
@@ -41,7 +39,6 @@ class ScreenRotationAnimation {
static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;
final Context mContext;
- final Display mDisplay;
Surface mSurface;
BlackFrame mBlackFrame;
int mWidth, mHeight;
@@ -58,18 +55,14 @@ class ScreenRotationAnimation {
final Transformation mEnterTransformation = new Transformation();
boolean mStarted;
- final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
final Matrix mSnapshotInitialMatrix = new Matrix();
final Matrix mSnapshotFinalMatrix = new Matrix();
final Matrix mTmpMatrix = new Matrix();
final float[] mTmpFloats = new float[9];
- public ScreenRotationAnimation(Context context, Display display, SurfaceSession session,
- boolean inTransaction) {
+ public ScreenRotationAnimation(Context context, SurfaceSession session,
+ boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
mContext = context;
- mDisplay = display;
-
- display.getRealMetrics(mDisplayMetrics);
Bitmap screenshot = Surface.screenshot(0, 0);
@@ -83,9 +76,9 @@ class ScreenRotationAnimation {
mWidth = screenshot.getWidth();
mHeight = screenshot.getHeight();
- mOriginalRotation = display.getRotation();
- mOriginalWidth = mDisplayMetrics.widthPixels;
- mOriginalHeight = mDisplayMetrics.heightPixels;
+ mOriginalRotation = originalRotation;
+ mOriginalWidth = originalWidth;
+ mOriginalHeight = originalHeight;
if (!inTransaction) {
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
@@ -106,7 +99,7 @@ class ScreenRotationAnimation {
WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
" FREEZE " + mSurface + ": CREATE");
- setRotation(display.getRotation());
+ setRotation(originalRotation);
if (mSurface != null) {
Rect dirty = new Rect(0, 0, mWidth, mHeight);
@@ -212,7 +205,7 @@ class ScreenRotationAnimation {
* Returns true if animating.
*/
public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
- float animationScale) {
+ float animationScale, int finalWidth, int finalHeight) {
if (mSurface == null) {
// Can't do animation.
return false;
@@ -248,16 +241,12 @@ class ScreenRotationAnimation {
break;
}
- mDisplay.getRealMetrics(mDisplayMetrics);
-
// Initialize the animations. This is a hack, redefining what "parent"
// means to allow supplying the last and next size. In this definition
// "%p" is the original (let's call it "previous") size, and "%" is the
// screen's current/new size.
- mEnterAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
- mOriginalWidth, mOriginalHeight);
- mExitAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
- mOriginalWidth, mOriginalHeight);
+ mEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
+ mExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
mStarted = false;
mExitAnimation.restrictDuration(maxAnimationDuration);
@@ -270,10 +259,8 @@ class ScreenRotationAnimation {
Surface.openTransaction();
try {
- final int w = mDisplayMetrics.widthPixels;
- final int h = mDisplayMetrics.heightPixels;
- Rect outer = new Rect(-w, -h, w*2, h*2);
- Rect inner = new Rect(0, 0, w, h);
+ Rect outer = new Rect(-finalWidth, -finalHeight, finalWidth * 2, finalHeight * 2);
+ Rect inner = new Rect(0, 0, finalWidth, finalHeight);
mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
} catch (Surface.OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/java/com/android/server/wm/StrictModeFlash.java
index 71b5952..768d2db 100644
--- a/services/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/java/com/android/server/wm/StrictModeFlash.java
@@ -38,9 +38,6 @@ class StrictModeFlash {
final int mThickness = 20;
public StrictModeFlash(Display display, SurfaceSession session) {
- final DisplayMetrics dm = new DisplayMetrics();
- display.getRealMetrics(dm);
-
try {
mSurface = new Surface(session, 0, "StrictModeFlash", -1, 1, 1, PixelFormat.TRANSLUCENT, 0);
} catch (Surface.OutOfResourcesException e) {
diff --git a/services/java/com/android/server/wm/Watermark.java b/services/java/com/android/server/wm/Watermark.java
index 375abe5..5497eb4 100644
--- a/services/java/com/android/server/wm/Watermark.java
+++ b/services/java/com/android/server/wm/Watermark.java
@@ -50,10 +50,7 @@ class Watermark {
int mLastDH;
boolean mDrawNeeded;
- Watermark(Display display, SurfaceSession session, String[] tokens) {
- final DisplayMetrics dm = new DisplayMetrics();
- display.getRealMetrics(dm);
-
+ Watermark(DisplayMetrics dm, SurfaceSession session, String[] tokens) {
if (false) {
Log.i(WindowManagerService.TAG, "*********************** WATERMARK");
for (int i=0; i<tokens.length; i++) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index be21ac0..f8059f5 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -465,6 +465,7 @@ public class WindowManagerService extends IWindowManager.Stub
Display mDisplay;
final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+ final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
@@ -5642,15 +5643,14 @@ public class WindowManagerService extends IWindowManager.Stub
}
config.orientation = orientation;
- DisplayMetrics dm = mDisplayMetrics;
- mDisplay.getRealMetrics(dm);
+ // Update real display metrics.
+ mDisplay.getMetricsWithSize(mRealDisplayMetrics, mCurDisplayWidth, mCurDisplayHeight);
- // Override display width and height with what we are computing,
- // to be sure they remain consistent.
- dm.widthPixels = dm.noncompatWidthPixels = mAppDisplayWidth
- = mPolicy.getNonDecorDisplayWidth(mRotation, dw);
- dm.heightPixels = dm.noncompatHeightPixels = mAppDisplayHeight
- = mPolicy.getNonDecorDisplayHeight(mRotation, dh);
+ // Update application display metrics.
+ final DisplayMetrics dm = mDisplayMetrics;
+ mAppDisplayWidth = mPolicy.getNonDecorDisplayWidth(mRotation, dw);
+ mAppDisplayHeight = mPolicy.getNonDecorDisplayHeight(mRotation, dh);
+ mDisplay.getMetricsWithSize(dm, mAppDisplayWidth, mAppDisplayHeight);
mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
mCompatDisplayMetrics);
@@ -6086,8 +6086,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mDisplay = wm.getDefaultDisplay();
- mInitialDisplayWidth = mDisplay.getRealWidth();
- mInitialDisplayHeight = mDisplay.getRealHeight();
+ mInitialDisplayWidth = mDisplay.getRawWidth();
+ mInitialDisplayHeight = mDisplay.getRawHeight();
int rot = mDisplay.getRotation();
if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
// If the screen is currently rotated, we need to swap the
@@ -6098,7 +6098,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth;
mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight;
- mInputManager.setDisplaySize(0, mDisplay.getRawWidth(), mDisplay.getRawHeight());
+ mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
+ mDisplay.getRawWidth(), mDisplay.getRawHeight(),
+ mDisplay.getRawExternalWidth(), mDisplay.getRawExternalHeight());
mPolicy.setInitialDisplaySize(mInitialDisplayWidth, mInitialDisplayHeight);
}
@@ -6602,6 +6604,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ public void getRealDisplaySize(Point size) {
+ synchronized(mWindowMap) {
+ size.x = mCurDisplayWidth;
+ size.y = mCurDisplayHeight;
+ }
+ }
+
public int getMaximumSizeDimension() {
synchronized(mWindowMap) {
// Do this based on the raw screen size, until we are smarter.
@@ -8687,7 +8696,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (mScreenRotationAnimation == null) {
mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
- mDisplay, mFxSession, inTransaction);
+ mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight,
+ mDisplay.getRotation());
}
if (!mScreenRotationAnimation.hasScreenshot()) {
Surface.freezeDisplay(0);
@@ -8717,7 +8727,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
&& mScreenRotationAnimation.hasScreenshot()) {
if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
- mTransitionAnimationScale)) {
+ mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
requestAnimationLocked(0);
} else {
mScreenRotationAnimation = null;
@@ -8797,7 +8807,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (line != null) {
String[] toks = line.split("%");
if (toks != null && toks.length > 0) {
- mWatermark = new Watermark(mDisplay, mFxSession, toks);
+ mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks);
}
}
} catch (FileNotFoundException e) {
@@ -9063,8 +9073,6 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
pw.print(" app=");
pw.print(mAppDisplayWidth); pw.print("x"); pw.print(mAppDisplayHeight);
- pw.print(" real="); pw.print(mDisplay.getRealWidth());
- pw.print("x"); pw.print(mDisplay.getRealHeight());
pw.print(" raw="); pw.print(mDisplay.getRawWidth());
pw.print("x"); pw.println(mDisplay.getRawHeight());
} else {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index d298ff7..cacb3e7 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -497,8 +497,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
- mService.updateWallpaperOffsetLocked(this, mService.mDisplay.getRealWidth(),
- mService.mDisplay.getRealHeight(), false);
+ mService.updateWallpaperOffsetLocked(this,
+ mService.mAppDisplayWidth, mService.mAppDisplayHeight, false);
}
if (WindowManagerService.localLOGV) {
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index de9c9d0..3414eea 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -166,7 +166,8 @@ public:
void dump(String8& dump);
- void setDisplaySize(int32_t displayId, int32_t width, int32_t height);
+ void setDisplaySize(int32_t displayId, int32_t width, int32_t height,
+ int32_t externalWidth, int32_t externalHeight);
void setDisplayOrientation(int32_t displayId, int32_t orientation);
status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
@@ -181,7 +182,7 @@ public:
/* --- InputReaderPolicyInterface implementation --- */
- virtual bool getDisplayInfo(int32_t displayId,
+ virtual bool getDisplayInfo(int32_t displayId, bool external,
int32_t* width, int32_t* height, int32_t* orientation);
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
@@ -221,7 +222,8 @@ private:
Mutex mLock;
struct Locked {
// Display size information.
- int32_t displayWidth, displayHeight; // -1 when initialized
+ int32_t displayWidth, displayHeight; // -1 when not initialized
+ int32_t displayExternalWidth, displayExternalHeight; // -1 when not initialized
int32_t displayOrientation;
// System UI visibility.
@@ -269,6 +271,8 @@ NativeInputManager::NativeInputManager(jobject contextObj,
AutoMutex _l(mLock);
mLocked.displayWidth = -1;
mLocked.displayHeight = -1;
+ mLocked.displayExternalWidth = -1;
+ mLocked.displayExternalHeight = -1;
mLocked.displayOrientation = ROTATION_0;
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
@@ -305,22 +309,24 @@ bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const c
return false;
}
-void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height) {
+void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height,
+ int32_t externalWidth, int32_t externalHeight) {
if (displayId == 0) {
{ // acquire lock
AutoMutex _l(mLock);
- if (mLocked.displayWidth == width && mLocked.displayHeight == height) {
- return;
- }
-
- mLocked.displayWidth = width;
- mLocked.displayHeight = height;
+ if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
+ mLocked.displayWidth = width;
+ mLocked.displayHeight = height;
- sp<PointerController> controller = mLocked.pointerController.promote();
- if (controller != NULL) {
- controller->setDisplaySize(width, height);
+ sp<PointerController> controller = mLocked.pointerController.promote();
+ if (controller != NULL) {
+ controller->setDisplaySize(width, height);
+ }
}
+
+ mLocked.displayExternalWidth = externalWidth;
+ mLocked.displayExternalHeight = externalHeight;
} // release lock
}
}
@@ -352,7 +358,7 @@ status_t NativeInputManager::unregisterInputChannel(JNIEnv* env,
return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel);
}
-bool NativeInputManager::getDisplayInfo(int32_t displayId,
+bool NativeInputManager::getDisplayInfo(int32_t displayId, bool external,
int32_t* width, int32_t* height, int32_t* orientation) {
bool result = false;
if (displayId == 0) {
@@ -360,10 +366,10 @@ bool NativeInputManager::getDisplayInfo(int32_t displayId,
if (mLocked.displayWidth > 0 && mLocked.displayHeight > 0) {
if (width) {
- *width = mLocked.displayWidth;
+ *width = external ? mLocked.displayExternalWidth : mLocked.displayWidth;
}
if (height) {
- *height = mLocked.displayHeight;
+ *height = external ? mLocked.displayExternalHeight : mLocked.displayHeight;
}
if (orientation) {
*orientation = mLocked.displayOrientation;
@@ -952,7 +958,7 @@ static void android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {
}
static void android_server_InputManager_nativeSetDisplaySize(JNIEnv* env, jclass clazz,
- jint displayId, jint width, jint height) {
+ jint displayId, jint width, jint height, jint externalWidth, jint externalHeight) {
if (checkInputManagerUnitialized(env)) {
return;
}
@@ -961,7 +967,7 @@ static void android_server_InputManager_nativeSetDisplaySize(JNIEnv* env, jclass
// to be passed in like this, not sure which is better but leaving it like this
// keeps the window manager in direct control of when display transitions propagate down
// to the input dispatcher
- gNativeInputManager->setDisplaySize(displayId, width, height);
+ gNativeInputManager->setDisplaySize(displayId, width, height, externalWidth, externalHeight);
}
static void android_server_InputManager_nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
@@ -1291,7 +1297,7 @@ static JNINativeMethod gInputManagerMethods[] = {
(void*) android_server_InputManager_nativeInit },
{ "nativeStart", "()V",
(void*) android_server_InputManager_nativeStart },
- { "nativeSetDisplaySize", "(III)V",
+ { "nativeSetDisplaySize", "(IIIII)V",
(void*) android_server_InputManager_nativeSetDisplaySize },
{ "nativeSetDisplayOrientation", "(II)V",
(void*) android_server_InputManager_nativeSetDisplayOrientation },
diff --git a/services/powermanager/Android.mk b/services/powermanager/Android.mk
new file mode 100644
index 0000000..d98b2da
--- /dev/null
+++ b/services/powermanager/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ IPowerManager.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libbinder
+
+LOCAL_MODULE:= libpowermanager
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/powermanager/IPowerManager.cpp b/services/powermanager/IPowerManager.cpp
new file mode 100644
index 0000000..a0f19d4
--- /dev/null
+++ b/services/powermanager/IPowerManager.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IPowerManager"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <powermanager/IPowerManager.h>
+
+namespace android {
+
+// must be kept in sync with IPowerManager.aidl
+enum {
+ ACQUIRE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION,
+ RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 4,
+};
+
+class BpPowerManager : public BpInterface<IPowerManager>
+{
+public:
+ BpPowerManager(const sp<IBinder>& impl)
+ : BpInterface<IPowerManager>(impl)
+ {
+ }
+
+ virtual status_t acquireWakeLock(int flags, const sp<IBinder>& lock, const String16& tag)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
+
+ data.writeInt32(flags);
+ data.writeStrongBinder(lock);
+ data.writeString16(tag);
+ // no WorkSource passed
+ data.writeInt32(0);
+ return remote()->transact(ACQUIRE_WAKE_LOCK, data, &reply);
+ }
+
+ virtual status_t releaseWakeLock(const sp<IBinder>& lock, int flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
+ data.writeStrongBinder(lock);
+ data.writeInt32(flags);
+ return remote()->transact(RELEASE_WAKE_LOCK, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(PowerManager, "android.os.IPowerManager");
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e0268fa..7d6a14d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -352,12 +352,13 @@ uint32_t Layer::doTransaction(uint32_t flags)
if (sizeChanged) {
// the size changed, we need to ask our client to request a new buffer
LOGD_IF(DEBUG_RESIZE,
+ "doTransaction: "
"resize (layer=%p), requested (%dx%d), drawing (%d,%d), "
- "fixedSize=%d",
+ "scalingMode=%d",
this,
int(temp.requested_w), int(temp.requested_h),
int(front.requested_w), int(front.requested_h),
- isFixedSize());
+ mCurrentScalingMode);
if (!isFixedSize()) {
// we're being resized and there is a freeze display request,
@@ -492,6 +493,14 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
// we now have the correct size, unfreeze the screen
mFreezeLock.clear();
}
+
+ LOGD_IF(DEBUG_RESIZE,
+ "lockPageFlip : "
+ " (layer=%p), buffer (%ux%u, tr=%02x), "
+ "requested (%dx%d)",
+ this,
+ bufWidth, bufHeight, mCurrentTransform,
+ front.requested_w, front.requested_h);
}
}
}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index ee5f3f5..1620405 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -29,6 +29,7 @@
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 504ba42..aab09ca 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -20,6 +20,7 @@ import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
@@ -27,6 +28,10 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
+import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
+import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
import static org.easymock.EasyMock.anyInt;
import static org.easymock.EasyMock.aryEq;
import static org.easymock.EasyMock.capture;
@@ -39,12 +44,14 @@ import static org.easymock.EasyMock.isA;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.IProcessObserver;
+import android.app.Notification;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
+import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
import android.net.LinkProperties;
@@ -95,7 +102,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
private IActivityManager mActivityManager;
private IPowerManager mPowerManager;
private INetworkStatsService mStatsService;
- private INetworkManagementService mNetworkManagement;
+ private INetworkManagementService mNetworkManager;
private INetworkPolicyListener mPolicyListener;
private TrustedTime mTime;
private IConnectivityManager mConnManager;
@@ -103,6 +110,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
private NetworkPolicyManagerService mService;
private IProcessObserver mProcessObserver;
+ private INetworkManagementEventObserver mNetworkObserver;
private Binder mStubBinder = new Binder();
@@ -141,6 +149,11 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
};
}
+
+ @Override
+ public void startActivity(Intent intent) {
+ // ignored
+ }
};
mPolicyDir = getContext().getFilesDir();
@@ -151,7 +164,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
mActivityManager = createMock(IActivityManager.class);
mPowerManager = createMock(IPowerManager.class);
mStatsService = createMock(INetworkStatsService.class);
- mNetworkManagement = createMock(INetworkManagementService.class);
+ mNetworkManager = createMock(INetworkManagementService.class);
mPolicyListener = createMock(INetworkPolicyListener.class);
mTime = createMock(TrustedTime.class);
mConnManager = createMock(IConnectivityManager.class);
@@ -159,7 +172,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
mService = new NetworkPolicyManagerService(
mServiceContext, mActivityManager, mPowerManager, mStatsService,
- mNetworkManagement, mTime, mPolicyDir);
+ mNetworkManager, mTime, mPolicyDir);
mService.bindConnectivityManager(mConnManager);
mService.bindNotificationManager(mNotifManager);
@@ -169,11 +182,17 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
mService.registerListener(mPolicyListener);
verifyAndReset();
- // catch the registered IProcessObserver during systemReady()
+ // catch IProcessObserver during systemReady()
final Capture<IProcessObserver> processObserver = new Capture<IProcessObserver>();
mActivityManager.registerProcessObserver(capture(processObserver));
expectLastCall().atLeastOnce();
+ // catch INetworkManagementEventObserver during systemReady()
+ final Capture<INetworkManagementEventObserver> networkObserver = new Capture<
+ INetworkManagementEventObserver>();
+ mNetworkManager.registerObserver(capture(networkObserver));
+ expectLastCall().atLeastOnce();
+
// expect to answer screen status during systemReady()
expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
expectTime(System.currentTimeMillis());
@@ -186,6 +205,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
verifyAndReset();
mProcessObserver = processObserver.getValue();
+ mNetworkObserver = networkObserver.getValue();
}
@@ -382,7 +402,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
- final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 5, 1024L, 1024L);
+ final NetworkPolicy policy = new NetworkPolicy(
+ sTemplateWifi, 5, 1024L, 1024L, SNOOZE_NEVER);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertEquals(expectedCycle, actualCycle);
}
@@ -392,7 +413,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
- final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 20, 1024L, 1024L);
+ final NetworkPolicy policy = new NetworkPolicy(
+ sTemplateWifi, 20, 1024L, 1024L, SNOOZE_NEVER);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertEquals(expectedCycle, actualCycle);
}
@@ -402,7 +424,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
final long currentTime = parseTime("2007-02-14T00:00:00.000Z");
final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
- final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 30, 1024L, 1024L);
+ final NetworkPolicy policy = new NetworkPolicy(
+ sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertEquals(expectedCycle, actualCycle);
}
@@ -412,7 +435,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
final long expectedCycle = parseTime("2007-03-01T00:00:00.000Z");
- final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 30, 1024L, 1024L);
+ final NetworkPolicy policy = new NetworkPolicy(
+ sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertEquals(expectedCycle, actualCycle);
}
@@ -432,6 +456,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
state = new NetworkState[] { buildWifi() };
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
expectTime(TIME_MAR_10 + elapsedRealtime);
+ expectClearNotifications();
future = expectMeteredIfacesChanged();
replay();
@@ -453,12 +478,14 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
// TODO: consider making strongly ordered mock
expectRemoveInterfaceQuota(TEST_IFACE);
expectSetInterfaceQuota(TEST_IFACE, 1536L);
+ expectRemoveInterfaceAlert(TEST_IFACE);
+ expectSetInterfaceAlert(TEST_IFACE, 512L);
expectClearNotifications();
future = expectMeteredIfacesChanged(TEST_IFACE);
replay();
- setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1024L, 2048L));
+ setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1024L, 2048L, SNOOZE_NEVER));
future.get();
verifyAndReset();
}
@@ -485,6 +512,131 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
verifyAndReset();
}
+ public void testOverWarningLimitNotification() throws Exception {
+ long elapsedRealtime = 0;
+ long currentTime = 0;
+ NetworkState[] state = null;
+ NetworkStats stats = null;
+ Future<Void> future;
+ Capture<String> tag;
+
+ final long TIME_FEB_15 = 1171497600000L;
+ final long TIME_MAR_10 = 1173484800000L;
+ final int CYCLE_DAY = 15;
+
+ // assign wifi policy
+ elapsedRealtime = 0;
+ currentTime = TIME_MAR_10 + elapsedRealtime;
+ state = new NetworkState[] {};
+
+ {
+ expectTime(currentTime);
+ expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+
+ expectClearNotifications();
+ future = expectMeteredIfacesChanged();
+
+ replay();
+ setNetworkPolicies(
+ new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1024L, 2048L, SNOOZE_NEVER));
+ future.get();
+ verifyAndReset();
+ }
+
+ // bring up wifi network
+ elapsedRealtime += MINUTE_IN_MILLIS;
+ currentTime = TIME_MAR_10 + elapsedRealtime;
+ stats = new NetworkStats(elapsedRealtime, 1)
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L);
+ state = new NetworkState[] { buildWifi() };
+
+ {
+ expectTime(currentTime);
+ expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+ expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
+ .andReturn(stats).atLeastOnce();
+
+ expectRemoveInterfaceQuota(TEST_IFACE);
+ expectSetInterfaceQuota(TEST_IFACE, 2048L);
+ expectRemoveInterfaceAlert(TEST_IFACE);
+ expectSetInterfaceAlert(TEST_IFACE, 1024L);
+
+ expectClearNotifications();
+ future = expectMeteredIfacesChanged(TEST_IFACE);
+
+ replay();
+ mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ future.get();
+ verifyAndReset();
+ }
+
+ // go over warning, which should kick notification
+ elapsedRealtime += MINUTE_IN_MILLIS;
+ currentTime = TIME_MAR_10 + elapsedRealtime;
+ stats = new NetworkStats(elapsedRealtime, 1)
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 1536L, 15L, 0L, 0L);
+
+ {
+ expectTime(currentTime);
+ expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
+ .andReturn(stats).atLeastOnce();
+
+ expectForceUpdate();
+ expectClearNotifications();
+ tag = expectEnqueueNotification();
+
+ replay();
+ mNetworkObserver.limitReached(null, TEST_IFACE);
+ assertNotificationType(TYPE_WARNING, tag.getValue());
+ verifyAndReset();
+ }
+
+ // go over limit, which should kick notification and dialog
+ elapsedRealtime += MINUTE_IN_MILLIS;
+ currentTime = TIME_MAR_10 + elapsedRealtime;
+ stats = new NetworkStats(elapsedRealtime, 1)
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 5120L, 512L, 0L, 0L);
+
+ {
+ expectTime(currentTime);
+ expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
+ .andReturn(stats).atLeastOnce();
+
+ expectForceUpdate();
+ expectClearNotifications();
+ tag = expectEnqueueNotification();
+
+ replay();
+ mNetworkObserver.limitReached(null, TEST_IFACE);
+ assertNotificationType(TYPE_LIMIT, tag.getValue());
+ verifyAndReset();
+ }
+
+ // now snooze policy, which should remove quota
+ elapsedRealtime += MINUTE_IN_MILLIS;
+ currentTime = TIME_MAR_10 + elapsedRealtime;
+
+ {
+ expectTime(currentTime);
+ expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+ expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
+ .andReturn(stats).atLeastOnce();
+
+ expectRemoveInterfaceQuota(TEST_IFACE);
+ expectRemoveInterfaceAlert(TEST_IFACE);
+
+ expectClearNotifications();
+ tag = expectEnqueueNotification();
+ future = expectMeteredIfacesChanged();
+
+ replay();
+ mService.snoozePolicy(sTemplateWifi);
+ future.get();
+ assertNotificationType(TYPE_LIMIT_SNOOZED, tag.getValue());
+ verifyAndReset();
+ }
+ }
+
private static long parseTime(String time) {
final Time result = new Time();
result.parse3339(time);
@@ -511,24 +663,46 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
}
+ private void expectForceUpdate() throws Exception {
+ mStatsService.forceUpdate();
+ expectLastCall().atLeastOnce();
+ }
+
private void expectClearNotifications() throws Exception {
mNotifManager.cancelNotificationWithTag(isA(String.class), isA(String.class), anyInt());
expectLastCall().anyTimes();
}
- private void expectSetInterfaceQuota(String iface, long quota) throws Exception {
- mNetworkManagement.setInterfaceQuota(iface, quota);
+ private Capture<String> expectEnqueueNotification() throws Exception {
+ final Capture<String> tag = new Capture<String>();
+ mNotifManager.enqueueNotificationWithTag(isA(String.class), capture(tag), anyInt(),
+ isA(Notification.class), isA(int[].class));
+ return tag;
+ }
+
+ private void expectSetInterfaceQuota(String iface, long quotaBytes) throws Exception {
+ mNetworkManager.setInterfaceQuota(iface, quotaBytes);
expectLastCall().atLeastOnce();
}
private void expectRemoveInterfaceQuota(String iface) throws Exception {
- mNetworkManagement.removeInterfaceQuota(iface);
+ mNetworkManager.removeInterfaceQuota(iface);
+ expectLastCall().atLeastOnce();
+ }
+
+ private void expectSetInterfaceAlert(String iface, long alertBytes) throws Exception {
+ mNetworkManager.setInterfaceAlert(iface, alertBytes);
+ expectLastCall().atLeastOnce();
+ }
+
+ private void expectRemoveInterfaceAlert(String iface) throws Exception {
+ mNetworkManager.removeInterfaceAlert(iface);
expectLastCall().atLeastOnce();
}
private void expectSetUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces)
throws Exception {
- mNetworkManagement.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+ mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
expectLastCall().atLeastOnce();
}
@@ -563,15 +737,20 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
}
+ private static void assertNotificationType(int expected, String actualTag) {
+ assertEquals(
+ Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1));
+ }
+
private void replay() {
EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
- mNetworkManagement, mTime, mConnManager, mNotifManager);
+ mNetworkManager, mTime, mConnManager, mNotifManager);
}
private void verifyAndReset() {
EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
- mNetworkManagement, mTime, mConnManager, mNotifManager);
+ mNetworkManager, mTime, mConnManager, mNotifManager);
EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
- mNetworkManagement, mTime, mConnManager, mNotifManager);
+ mNetworkManager, mTime, mConnManager, mNotifManager);
}
}