Merge "Revert to using epoll_wait()." into gingerbread
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 6533600..da4d56f 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -77,6 +77,11 @@
eOrientationSwapMask = 0x01
};
+ enum {
+ eElectronBeamAnimationOn = 0x01,
+ eElectronBeamAnimationOff = 0x10
+ };
+
// flags for setOrientation
enum {
eOrientationAnimationDisable = 0x00000001
@@ -118,6 +123,9 @@
uint32_t* width, uint32_t* height, PixelFormat* format,
uint32_t reqWidth, uint32_t reqHeight) = 0;
+ virtual status_t turnElectronBeamOff(int32_t mode) = 0;
+ virtual status_t turnElectronBeamOn(int32_t mode) = 0;
+
/* Signal surfaceflinger that there might be some work to do
* This is an ASYNCHRONOUS call.
*/
@@ -142,7 +150,9 @@
FREEZE_DISPLAY,
UNFREEZE_DISPLAY,
SIGNAL,
- CAPTURE_SCREEN
+ CAPTURE_SCREEN,
+ TURN_ELECTRON_BEAM_OFF,
+ TURN_ELECTRON_BEAM_ON
};
virtual status_t onTransact( uint32_t code,
diff --git a/include/ui/Input.h b/include/ui/Input.h
index ee40b85..8c6018b 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -71,6 +71,8 @@
/*
* Flags that flow alongside events in the input dispatch system to help with certain
* policy decisions such as waking from device sleep.
+ *
+ * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java.
*/
enum {
/* These flags originate in RawEvents and are generally set in the key map.
@@ -93,6 +95,10 @@
// Indicates that the input event was injected.
POLICY_FLAG_INJECTED = 0x01000000,
+ // Indicates that the input event is from a trusted source such as a directly attached
+ // input device or an application with system-wide event injection permission.
+ POLICY_FLAG_TRUSTED = 0x02000000,
+
/* These flags are set by the input reader policy as it intercepts each event. */
// Indicates that the screen was off when the event was received and the event
@@ -102,6 +108,11 @@
// Indicates that the screen was dim when the event was received and the event
// should brighten the device.
POLICY_FLAG_BRIGHT_HERE = 0x20000000,
+
+ // Indicates that the event should be dispatched to applications.
+ // The input event should still be sent to the InputDispatcher so that it can see all
+ // input events received include those that it will not deliver.
+ POLICY_FLAG_PASS_TO_USER = 0x40000000,
};
/*
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 47c5326..3599163 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -282,10 +282,35 @@
*/
virtual int32_t getMaxEventsPerSecond() = 0;
+ /* Intercepts a key event immediately before queueing it.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing such as updating policy flags.
+ *
+ * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
+ * should be dispatched to applications.
+ */
+ virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
+ int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
+ uint32_t& policyFlags) = 0;
+
+ /* Intercepts a generic touch, trackball or other event before queueing it.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing such as updating policy flags.
+ *
+ * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
+ * should be dispatched to applications.
+ */
+ virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0;
+
/* Allows the policy a chance to intercept a key before dispatching. */
virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
+ /* Notifies the policy about switch events.
+ */
+ virtual void notifySwitch(nsecs_t when,
+ int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0;
+
/* Poke user activity for an event dispatched to a window. */
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0;
@@ -333,6 +358,8 @@
int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) = 0;
+ virtual void notifySwitch(nsecs_t when,
+ int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0;
/* Injects an input event and optionally waits for sync.
* The synchronization mode determines whether the method blocks while waiting for
@@ -408,6 +435,8 @@
int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime);
+ virtual void notifySwitch(nsecs_t when,
+ int32_t switchCode, int32_t switchValue, uint32_t policyFlags) ;
virtual int32_t injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis);
@@ -447,6 +476,7 @@
mutable int32_t refCount;
int32_t type;
nsecs_t eventTime;
+ uint32_t policyFlags;
InjectionState* injectionState;
bool dispatchInProgress; // initially false, set to true while dispatching
@@ -460,7 +490,6 @@
struct KeyEntry : EventEntry {
int32_t deviceId;
int32_t source;
- uint32_t policyFlags;
int32_t action;
int32_t flags;
int32_t keyCode;
@@ -489,7 +518,6 @@
struct MotionEntry : EventEntry {
int32_t deviceId;
int32_t source;
- uint32_t policyFlags;
int32_t action;
int32_t flags;
int32_t metaState;
@@ -664,7 +692,8 @@
Pool<DispatchEntry> mDispatchEntryPool;
Pool<CommandEntry> mCommandEntryPool;
- void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime);
+ void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime,
+ uint32_t policyFlags);
void releaseEventEntryInjectionState(EventEntry* entry);
};
@@ -685,21 +714,19 @@
BROKEN
};
+ // Specifies the sources to cancel.
+ enum CancelationOptions {
+ CANCEL_ALL_EVENTS = 0,
+ CANCEL_POINTER_EVENTS = 1,
+ CANCEL_NON_POINTER_EVENTS = 2,
+ };
+
InputState();
~InputState();
// Returns true if there is no state to be canceled.
bool isNeutral() const;
- // Returns true if the input state believes it is out of sync.
- bool isOutOfSync() const;
-
- // Sets the input state to be out of sync if it is not neutral.
- void setOutOfSync();
-
- // Resets the input state out of sync flag.
- void resetOutOfSync();
-
// Records tracking information for an event that has just been published.
// Returns whether the event is consistent with the current input state.
Consistency trackEvent(const EventEntry* entry);
@@ -712,16 +739,14 @@
// Returns whether the event is consistent with the current input state.
Consistency trackMotion(const MotionEntry* entry);
- // Synthesizes cancelation events for the current state.
- void synthesizeCancelationEvents(Allocator* allocator,
- Vector<EventEntry*>& outEvents) const;
+ // Synthesizes cancelation events for the current state and resets the tracked state.
+ void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator,
+ Vector<EventEntry*>& outEvents, CancelationOptions options);
// Clears the current state.
void clear();
private:
- bool mIsOutOfSync;
-
struct KeyMemento {
int32_t deviceId;
int32_t source;
@@ -745,6 +770,8 @@
Vector<KeyMemento> mKeyMementos;
Vector<MotionMemento> mMotionMementos;
+
+ static bool shouldCancelEvent(int32_t eventSource, CancelationOptions options);
};
/* Manages the dispatch state associated with a single input channel. */
@@ -794,6 +821,13 @@
status_t initialize();
};
+ enum DropReason {
+ DROP_REASON_NOT_DROPPED = 0,
+ DROP_REASON_POLICY = 1,
+ DROP_REASON_APP_SWITCH = 2,
+ DROP_REASON_DISABLED = 3,
+ };
+
sp<InputDispatcherPolicyInterface> mPolicy;
Mutex mLock;
@@ -813,12 +847,16 @@
// Enqueues an inbound event. Returns true if mLooper->wake() should be called.
bool enqueueInboundEventLocked(EventEntry* entry);
+ // Cleans up input state when dropping an inbound event.
+ void dropInboundEventLocked(EventEntry* entry, DropReason dropReason);
+
// App switch latency optimization.
+ bool mAppSwitchSawKeyDown;
nsecs_t mAppSwitchDueTime;
- static bool isAppSwitchKey(int32_t keyCode);
+ static bool isAppSwitchKeyCode(int32_t keyCode);
+ bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry);
bool isAppSwitchPendingLocked();
- bool detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry);
void resetPendingAppSwitchLocked(bool handled);
// All registered connections mapped by receive pipe file descriptor.
@@ -840,7 +878,7 @@
// Event injection and synchronization.
Condition mInjectionResultAvailableCondition;
- EventEntry* createEntryFromInjectedInputEventLocked(const InputEvent* event);
+ bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
Condition mInjectionSyncFinishedCondition;
@@ -875,7 +913,6 @@
void drainInboundQueueLocked();
void releasePendingEventLocked();
void releaseInboundEventLocked(EventEntry* entry);
- bool isEventFromReliableSourceLocked(EventEntry* entry);
// Dispatch state.
bool mDispatchEnabled;
@@ -922,10 +959,10 @@
nsecs_t currentTime, ConfigurationChangedEntry* entry);
bool dispatchKeyLocked(
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
- bool dropEvent, nsecs_t* nextWakeupTime);
+ DropReason* dropReason, nsecs_t* nextWakeupTime);
bool dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry,
- bool dropEvent, nsecs_t* nextWakeupTime);
+ DropReason* dropReason, nsecs_t* nextWakeupTime);
void dispatchEventToCurrentInputTargetsLocked(
nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
@@ -984,11 +1021,17 @@
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
- void abortDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- bool broken);
+ void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void drainOutboundQueueLocked(Connection* connection);
static int handleReceiveCallback(int receiveFd, int events, void* data);
+ void synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CancelationOptions options, const char* reason);
+ void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
+ InputState::CancelationOptions options, const char* reason);
+ void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
+ InputState::CancelationOptions options, const char* reason);
+
// Splitting motion events across windows.
MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 3619189..c15e382 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -87,49 +87,12 @@
ROTATION_270 = 3
};
- /* Actions returned by interceptXXX methods. */
- enum {
- // The input dispatcher should do nothing and discard the input unless other
- // flags are set.
- ACTION_NONE = 0,
-
- // The input dispatcher should dispatch the input to the application.
- ACTION_DISPATCH = 0x00000001,
- };
-
/* Gets information about the display with the specified id.
* Returns true if the display info is available, false otherwise.
*/
virtual bool getDisplayInfo(int32_t displayId,
int32_t* width, int32_t* height, int32_t* orientation) = 0;
- /* Intercepts a key event.
- * The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing such as updating policy flags.
- *
- * Returns a policy action constant such as ACTION_DISPATCH.
- */
- virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
- bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) = 0;
-
- /* Intercepts a switch event.
- * The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing such as updating policy flags.
- *
- * Switches are not dispatched to applications so this method should
- * usually return ACTION_NONE.
- */
- virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
- uint32_t& policyFlags) = 0;
-
- /* Intercepts a generic touch, trackball or other event.
- * The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing such as updating policy flags.
- *
- * Returns a policy action constant such as ACTION_DISPATCH.
- */
- virtual int32_t interceptGeneric(nsecs_t when, uint32_t& policyFlags) = 0;
-
/* Determines whether to turn on some hacks we have to improve the touch interaction with a
* certain device whose screen currently is not all that good.
*/
@@ -403,8 +366,6 @@
protected:
InputDevice* mDevice;
InputReaderContext* mContext;
-
- bool applyStandardPolicyActions(nsecs_t when, int32_t policyActions);
};
@@ -466,8 +427,6 @@
void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
uint32_t policyFlags);
- void applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags,
- bool down, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime);
ssize_t findKeyDownLocked(int32_t scanCode);
};
@@ -525,8 +484,6 @@
void initializeLocked();
void sync(nsecs_t when);
- void applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
- PointerCoords* pointerCoords, nsecs_t downTime);
};
@@ -829,10 +786,6 @@
BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
int32_t motionEventAction);
- void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
- int32_t keyEventAction, int32_t keyEventFlags,
- int32_t keyCode, int32_t scanCode, nsecs_t downTime);
-
bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y);
diff --git a/include/utils/ObbFile.h b/include/utils/ObbFile.h
index 5243f50..47559cd 100644
--- a/include/utils/ObbFile.h
+++ b/include/utils/ObbFile.h
@@ -27,6 +27,7 @@
// OBB flags (bit 0)
#define OBB_OVERLAY (1 << 0)
+#define OBB_SALTED (1 << 1)
class ObbFile : public RefBase {
protected:
@@ -70,6 +71,26 @@
mFlags = flags;
}
+ const unsigned char* getSalt(size_t* length) const {
+ if ((mFlags & OBB_SALTED) == 0) {
+ *length = 0;
+ return NULL;
+ }
+
+ *length = sizeof(mSalt);
+ return mSalt;
+ }
+
+ bool setSalt(const unsigned char* salt, size_t length) {
+ if (length != sizeof(mSalt)) {
+ return false;
+ }
+
+ memcpy(mSalt, salt, sizeof(mSalt));
+ mFlags |= OBB_SALTED;
+ return true;
+ }
+
bool isOverlay() {
return (mFlags & OBB_OVERLAY) == OBB_OVERLAY;
}
@@ -103,6 +124,12 @@
/* Flags for this OBB type. */
int32_t mFlags;
+ /* Whether the file is salted. */
+ bool mSalted;
+
+ /* The encryption salt. */
+ unsigned char mSalt[8];
+
const char* mFileName;
size_t mFileSize;
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index d676f5e..969ee79 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -142,6 +142,24 @@
return reply.readInt32();
}
+ virtual status_t turnElectronBeamOff(int32_t mode)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_OFF, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t turnElectronBeamOn(int32_t mode)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_ON, data, &reply);
+ return reply.readInt32();
+ }
+
virtual void signal() const
{
Parcel data, reply;
@@ -224,6 +242,18 @@
reply->writeInt32(f);
reply->writeInt32(res);
} break;
+ case TURN_ELECTRON_BEAM_OFF: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t mode = data.readInt32();
+ status_t res = turnElectronBeamOff(mode);
+ reply->writeInt32(res);
+ }
+ case TURN_ELECTRON_BEAM_ON: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t mode = data.readInt32();
+ status_t res = turnElectronBeamOn(mode);
+ reply->writeInt32(res);
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index c0be3a0..944731d 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -439,11 +439,10 @@
// Since mFDs[0] is used for inotify, we process regular events starting at index 1.
mInputDeviceIndex += 1;
if (mInputDeviceIndex >= mFDCount) {
- mInputDeviceIndex = 0;
break;
}
- const struct pollfd &pfd = mFDs[mInputDeviceIndex];
+ const struct pollfd& pfd = mFDs[mInputDeviceIndex];
if (pfd.revents & POLLIN) {
int32_t readSize = read(pfd.fd, mInputBufferData,
sizeof(struct input_event) * INPUT_BUFFER_SIZE);
@@ -460,11 +459,17 @@
}
}
+#if HAVE_INOTIFY
// readNotify() will modify mFDs and mFDCount, so this must be done after
// processing all other events.
if(mFDs[0].revents & POLLIN) {
readNotify(mFDs[0].fd);
+ mFDs[0].revents = 0;
+ continue; // report added or removed devices immediately
}
+#endif
+
+ mInputDeviceIndex = 0;
// Poll for events. Mind the wake lock dance!
// We hold a wake lock at all times except during poll(). This works due to some
@@ -482,7 +487,7 @@
if (pollResult <= 0) {
if (errno != EINTR) {
- LOGW("select failed (errno=%d)\n", errno);
+ LOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
}
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index fe8555d..6ba19d7 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -95,16 +95,19 @@
return true;
}
-static bool isValidMotionAction(int32_t action) {
+static bool isValidMotionAction(int32_t action, size_t pointerCount) {
switch (action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_MOVE:
- case AMOTION_EVENT_ACTION_POINTER_DOWN:
- case AMOTION_EVENT_ACTION_POINTER_UP:
case AMOTION_EVENT_ACTION_OUTSIDE:
return true;
+ case AMOTION_EVENT_ACTION_POINTER_DOWN:
+ case AMOTION_EVENT_ACTION_POINTER_UP: {
+ int32_t index = getMotionEventActionPointerIndex(action);
+ return index >= 0 && size_t(index) < pointerCount;
+ }
default:
return false;
}
@@ -112,7 +115,7 @@
static bool validateMotionEvent(int32_t action, size_t pointerCount,
const int32_t* pointerIds) {
- if (! isValidMotionAction(action)) {
+ if (! isValidMotionAction(action, pointerCount)) {
LOGE("Motion event has invalid action code 0x%x", action);
return false;
}
@@ -235,16 +238,6 @@
resetKeyRepeatLocked();
}
- // If dispatching is disabled, drop all events in the queue.
- if (! mDispatchEnabled) {
- if (mPendingEvent || ! mInboundQueue.isEmpty()) {
- LOGI("Dropping pending events because input dispatch is disabled.");
- releasePendingEventLocked();
- drainInboundQueueLocked();
- }
- return;
- }
-
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
if (mDispatchFrozen) {
#if DEBUG_FOCUS
@@ -294,7 +287,11 @@
// samples may be appended to this event by the time the throttling timeout
// expires.
// TODO Make this smarter and consider throttling per device independently.
- if (entry->type == EventEntry::TYPE_MOTION) {
+ if (entry->type == EventEntry::TYPE_MOTION
+ && !isAppSwitchDue
+ && mDispatchEnabled
+ && (entry->policyFlags & POLICY_FLAG_PASS_TO_USER)
+ && !entry->isInjected()) {
MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
int32_t deviceId = motionEntry->deviceId;
uint32_t source = motionEntry->source;
@@ -347,39 +344,43 @@
// Now we have an event to dispatch.
assert(mPendingEvent != NULL);
bool done = false;
+ DropReason dropReason = DROP_REASON_NOT_DROPPED;
+ if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
+ dropReason = DROP_REASON_POLICY;
+ } else if (!mDispatchEnabled) {
+ dropReason = DROP_REASON_DISABLED;
+ }
switch (mPendingEvent->type) {
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
ConfigurationChangedEntry* typedEntry =
static_cast<ConfigurationChangedEntry*>(mPendingEvent);
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
+ dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
break;
}
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
- bool appSwitchKey = isAppSwitchKey(typedEntry->keyCode);
- bool dropEvent = isAppSwitchDue && ! appSwitchKey;
- done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, dropEvent,
- nextWakeupTime);
- if (done) {
- if (dropEvent) {
- LOGI("Dropped key because of pending overdue app switch.");
- } else if (appSwitchKey) {
+ if (isAppSwitchDue) {
+ if (isAppSwitchKeyEventLocked(typedEntry)) {
resetPendingAppSwitchLocked(true);
+ isAppSwitchDue = false;
+ } else if (dropReason == DROP_REASON_NOT_DROPPED) {
+ dropReason = DROP_REASON_APP_SWITCH;
}
}
+ done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout,
+ &dropReason, nextWakeupTime);
break;
}
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
- bool dropEvent = isAppSwitchDue;
- done = dispatchMotionLocked(currentTime, typedEntry, dropEvent, nextWakeupTime);
- if (done) {
- if (dropEvent) {
- LOGI("Dropped motion because of pending overdue app switch.");
- }
+ if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
+ dropReason = DROP_REASON_APP_SWITCH;
}
+ done = dispatchMotionLocked(currentTime, typedEntry,
+ &dropReason, nextWakeupTime);
break;
}
@@ -389,6 +390,10 @@
}
if (done) {
+ if (dropReason != DROP_REASON_NOT_DROPPED) {
+ dropInboundEventLocked(mPendingEvent, dropReason);
+ }
+
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
@@ -399,36 +404,85 @@
mInboundQueue.enqueueAtTail(entry);
switch (entry->type) {
- case EventEntry::TYPE_KEY:
- needWake |= detectPendingAppSwitchLocked(static_cast<KeyEntry*>(entry));
+ case EventEntry::TYPE_KEY: {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
+ if (isAppSwitchKeyEventLocked(keyEntry)) {
+ if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
+ mAppSwitchSawKeyDown = true;
+ } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
+ if (mAppSwitchSawKeyDown) {
+#if DEBUG_APP_SWITCH
+ LOGD("App switch is pending!");
+#endif
+ mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
+ mAppSwitchSawKeyDown = false;
+ needWake = true;
+ }
+ }
+ }
break;
}
+ }
return needWake;
}
-bool InputDispatcher::isAppSwitchKey(int32_t keyCode) {
+void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
+ const char* reason;
+ switch (dropReason) {
+ case DROP_REASON_POLICY:
+#if DEBUG_INBOUND_EVENT_DETAILS
+ LOGD("Dropped event because policy consumed it.");
+#endif
+ reason = "inbound event was dropped because the policy consumed it";
+ break;
+ case DROP_REASON_DISABLED:
+ LOGI("Dropped event because input dispatch is disabled.");
+ reason = "inbound event was dropped because input dispatch is disabled";
+ break;
+ case DROP_REASON_APP_SWITCH:
+ LOGI("Dropped event because of pending overdue app switch.");
+ reason = "inbound event was dropped because of pending overdue app switch";
+ break;
+ default:
+ assert(false);
+ return;
+ }
+
+ switch (entry->type) {
+ case EventEntry::TYPE_KEY:
+ synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CANCEL_NON_POINTER_EVENTS, reason);
+ break;
+ case EventEntry::TYPE_MOTION: {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
+ if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
+ synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CANCEL_POINTER_EVENTS, reason);
+ } else {
+ synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CANCEL_NON_POINTER_EVENTS, reason);
+ }
+ break;
+ }
+ }
+}
+
+bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) {
return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL;
}
+bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) {
+ return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
+ && isAppSwitchKeyCode(keyEntry->keyCode)
+ && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED)
+ && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER);
+}
+
bool InputDispatcher::isAppSwitchPendingLocked() {
return mAppSwitchDueTime != LONG_LONG_MAX;
}
-bool InputDispatcher::detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry) {
- if (inboundKeyEntry->action == AKEY_EVENT_ACTION_UP
- && ! (inboundKeyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
- && isAppSwitchKey(inboundKeyEntry->keyCode)
- && isEventFromReliableSourceLocked(inboundKeyEntry)) {
-#if DEBUG_APP_SWITCH
- LOGD("App switch is pending!");
-#endif
- mAppSwitchDueTime = inboundKeyEntry->eventTime + APP_SWITCH_TIMEOUT;
- return true; // need wake
- }
- return false;
-}
-
void InputDispatcher::resetPendingAppSwitchLocked(bool handled) {
mAppSwitchDueTime = LONG_LONG_MAX;
@@ -489,14 +543,6 @@
mAllocator.releaseEventEntry(entry);
}
-bool InputDispatcher::isEventFromReliableSourceLocked(EventEntry* entry) {
- InjectionState* injectionState = entry->injectionState;
- return ! injectionState
- || injectionState->injectorUid == 0
- || mPolicy->checkInjectEventsPermissionNonReentrant(
- injectionState->injectorPid, injectionState->injectorUid);
-}
-
void InputDispatcher::resetKeyRepeatLocked() {
if (mKeyRepeatState.lastKeyEntry) {
mAllocator.releaseKeyEntry(mKeyRepeatState.lastKeyEntry);
@@ -509,7 +555,8 @@
KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
// Reuse the repeated key entry if it is otherwise unreferenced.
- uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK;
+ uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK)
+ | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED;
if (entry->refCount == 1) {
mAllocator.recycleKeyEntry(entry);
entry->eventTime = currentTime;
@@ -558,19 +605,13 @@
bool InputDispatcher::dispatchKeyLocked(
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
- bool dropEvent, nsecs_t* nextWakeupTime) {
+ DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
- bool trusted;
- if (! dropEvent && mFocusedWindow) {
- trusted = checkInjectionPermission(mFocusedWindow, entry->injectionState);
- } else {
- trusted = isEventFromReliableSourceLocked(entry);
- }
- if (trusted) {
+ if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
- if (! dropEvent && mFocusedWindow) {
+ if (mFocusedWindow) {
commandEntry->inputChannel = mFocusedWindow->inputChannel;
}
commandEntry->keyEntry = entry;
@@ -580,15 +621,16 @@
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
}
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
- resetTargetsLocked();
- setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_SUCCEEDED);
- return true;
+ if (*dropReason == DROP_REASON_NOT_DROPPED) {
+ *dropReason = DROP_REASON_POLICY;
+ }
}
// Clean up if dropping the event.
- if (dropEvent) {
+ if (*dropReason != DROP_REASON_NOT_DROPPED) {
resetTargetsLocked();
- setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
+ setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
+ ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
@@ -598,7 +640,8 @@
if (entry->repeatCount == 0
&& entry->action == AKEY_EVENT_ACTION_DOWN
- && ! entry->isInjected()) {
+ && (entry->policyFlags & POLICY_FLAG_TRUSTED)
+ && !entry->isInjected()) {
if (mKeyRepeatState.lastKeyEntry
&& mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
// We have seen two identical key downs in a row which indicates that the device
@@ -663,11 +706,12 @@
}
bool InputDispatcher::dispatchMotionLocked(
- nsecs_t currentTime, MotionEntry* entry, bool dropEvent, nsecs_t* nextWakeupTime) {
+ nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Clean up if dropping the event.
- if (dropEvent) {
+ if (*dropReason != DROP_REASON_NOT_DROPPED) {
resetTargetsLocked();
- setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
+ setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
+ ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
@@ -793,9 +837,11 @@
prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
resumeWithAppendedMotionSample);
} else {
- LOGW("Framework requested delivery of an input event to channel '%s' but it "
- "is not registered with the input dispatcher.",
+#if DEBUG_FOCUS
+ LOGD("Dropping event delivery to target with channel '%s' because it "
+ "is no longer registered with the input dispatcher.",
inputTarget.inputChannel->getName().string());
+#endif
}
}
}
@@ -876,7 +922,9 @@
ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- connection->inputState.setOutOfSync();
+ synthesizeCancelationEventsForConnectionLocked(
+ connection, InputState::CANCEL_ALL_EVENTS,
+ "application not responding");
}
}
}
@@ -1236,7 +1284,9 @@
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
// First pointer went down.
if (mTouchState.down) {
- LOGW("Pointer down received while already down.");
+#if DEBUG_FOCUS
+ LOGD("Pointer down received while already down.");
+#endif
}
} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
// One pointer went up.
@@ -1307,23 +1357,19 @@
bool InputDispatcher::checkInjectionPermission(const InputWindow* window,
const InjectionState* injectionState) {
if (injectionState
- && injectionState->injectorUid > 0
- && (window == NULL || window->ownerUid != injectionState->injectorUid)) {
- bool result = mPolicy->checkInjectEventsPermissionNonReentrant(
- injectionState->injectorPid, injectionState->injectorUid);
- if (! result) {
- if (window) {
- LOGW("Permission denied: injecting event from pid %d uid %d to window "
- "with input channel %s owned by uid %d",
- injectionState->injectorPid, injectionState->injectorUid,
- window->inputChannel->getName().string(),
- window->ownerUid);
- } else {
- LOGW("Permission denied: injecting event from pid %d uid %d",
- injectionState->injectorPid, injectionState->injectorUid);
- }
- return false;
+ && (window == NULL || window->ownerUid != injectionState->injectorUid)
+ && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
+ if (window) {
+ LOGW("Permission denied: injecting event from pid %d uid %d to window "
+ "with input channel %s owned by uid %d",
+ injectionState->injectorPid, injectionState->injectorUid,
+ window->inputChannel->getName().string(),
+ window->ownerUid);
+ } else {
+ LOGW("Permission denied: injecting event from pid %d uid %d",
+ injectionState->injectorPid, injectionState->injectorUid);
}
+ return false;
}
return true;
}
@@ -1408,8 +1454,10 @@
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::STATUS_NORMAL) {
- LOGW("channel '%s' ~ Dropping event because the channel status is %s",
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ Dropping event because the channel status is %s",
connection->getInputChannelName(), connection->getStatusLabel());
+#endif
return;
}
@@ -1508,40 +1556,6 @@
}
}
- // Bring the input state back in line with reality in case it drifted off during an ANR.
- if (connection->inputState.isOutOfSync()) {
- mTempCancelationEvents.clear();
- connection->inputState.synthesizeCancelationEvents(& mAllocator, mTempCancelationEvents);
- connection->inputState.resetOutOfSync();
-
- if (! mTempCancelationEvents.isEmpty()) {
- LOGI("channel '%s' ~ Generated %d cancelation events to bring channel back in sync "
- "with reality.",
- connection->getInputChannelName(), mTempCancelationEvents.size());
-
- for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
- EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
- switch (cancelationEventEntry->type) {
- case EventEntry::TYPE_KEY:
- logOutboundKeyDetailsLocked(" ",
- static_cast<KeyEntry*>(cancelationEventEntry));
- break;
- case EventEntry::TYPE_MOTION:
- logOutboundMotionDetailsLocked(" ",
- static_cast<MotionEntry*>(cancelationEventEntry));
- break;
- }
-
- DispatchEntry* cancelationDispatchEntry =
- mAllocator.obtainDispatchEntry(cancelationEventEntry,
- 0, inputTarget->xOffset, inputTarget->yOffset); // increments ref
- connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry);
-
- mAllocator.releaseEventEntry(cancelationEventEntry);
- }
- }
- }
-
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref
@@ -1635,7 +1649,7 @@
if (status) {
LOGE("channel '%s' ~ Could not publish key event, "
"status=%d", connection->getInputChannelName(), status);
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
return;
}
break;
@@ -1685,7 +1699,7 @@
if (status) {
LOGE("channel '%s' ~ Could not publish motion event, "
"status=%d", connection->getInputChannelName(), status);
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
return;
}
@@ -1706,7 +1720,7 @@
LOGE("channel '%s' ~ Could not append motion sample "
"for a reason other than out of memory, status=%d",
connection->getInputChannelName(), status);
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
return;
}
}
@@ -1727,7 +1741,7 @@
if (status) {
LOGE("channel '%s' ~ Could not send dispatch signal, status=%d",
connection->getInputChannelName(), status);
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
return;
}
@@ -1764,7 +1778,7 @@
if (status) {
LOGE("channel '%s' ~ Could not reset publisher, status=%d",
connection->getInputChannelName(), status);
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
return;
}
@@ -1806,28 +1820,23 @@
deactivateConnectionLocked(connection.get());
}
-void InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection, bool broken) {
+void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
+ const sp<Connection>& connection) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ abortDispatchCycle - broken=%s",
+ LOGD("channel '%s' ~ abortBrokenDispatchCycle - broken=%s",
connection->getInputChannelName(), toString(broken));
#endif
- // Input state will no longer be realistic.
- connection->inputState.setOutOfSync();
-
// Clear the outbound queue.
drainOutboundQueueLocked(connection.get());
- // Handle the case where the connection appears to be unrecoverably broken.
+ // The connection appears to be unrecoverably broken.
// Ignore already broken or zombie connections.
- if (broken) {
- if (connection->status == Connection::STATUS_NORMAL) {
- connection->status = Connection::STATUS_BROKEN;
+ if (connection->status == Connection::STATUS_NORMAL) {
+ connection->status = Connection::STATUS_BROKEN;
- // Notify other system components.
- onDispatchCycleBrokenLocked(currentTime, connection);
- }
+ // Notify other system components.
+ onDispatchCycleBrokenLocked(currentTime, connection);
}
}
@@ -1862,7 +1871,7 @@
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. "
"events=0x%x", connection->getInputChannelName(), events);
- d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ d->abortBrokenDispatchCycleLocked(currentTime, connection);
d->runCommandsLockedInterruptible();
return 0; // remove the callback
}
@@ -1877,7 +1886,7 @@
if (status) {
LOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName(), status);
- d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ d->abortBrokenDispatchCycleLocked(currentTime, connection);
d->runCommandsLockedInterruptible();
return 0; // remove the callback
}
@@ -1888,6 +1897,77 @@
} // release lock
}
+void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CancelationOptions options, const char* reason) {
+ for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) {
+ synthesizeCancelationEventsForConnectionLocked(
+ mConnectionsByReceiveFd.valueAt(i), options, reason);
+ }
+}
+
+void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
+ const sp<InputChannel>& channel, InputState::CancelationOptions options,
+ const char* reason) {
+ ssize_t index = getConnectionIndexLocked(channel);
+ if (index >= 0) {
+ synthesizeCancelationEventsForConnectionLocked(
+ mConnectionsByReceiveFd.valueAt(index), options, reason);
+ }
+}
+
+void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
+ const sp<Connection>& connection, InputState::CancelationOptions options,
+ const char* reason) {
+ nsecs_t currentTime = now();
+
+ mTempCancelationEvents.clear();
+ connection->inputState.synthesizeCancelationEvents(currentTime, & mAllocator,
+ mTempCancelationEvents, options);
+
+ if (! mTempCancelationEvents.isEmpty()
+ && connection->status != Connection::STATUS_BROKEN) {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ LOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
+ "with reality: %s, options=%d.",
+ connection->getInputChannelName(), mTempCancelationEvents.size(), reason, options);
+#endif
+ for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
+ EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
+ switch (cancelationEventEntry->type) {
+ case EventEntry::TYPE_KEY:
+ logOutboundKeyDetailsLocked("cancel - ",
+ static_cast<KeyEntry*>(cancelationEventEntry));
+ break;
+ case EventEntry::TYPE_MOTION:
+ logOutboundMotionDetailsLocked("cancel - ",
+ static_cast<MotionEntry*>(cancelationEventEntry));
+ break;
+ }
+
+ int32_t xOffset, yOffset;
+ const InputWindow* window = getWindowLocked(connection->inputChannel);
+ if (window) {
+ xOffset = -window->frameLeft;
+ yOffset = -window->frameTop;
+ } else {
+ xOffset = 0;
+ yOffset = 0;
+ }
+
+ DispatchEntry* cancelationDispatchEntry =
+ mAllocator.obtainDispatchEntry(cancelationEventEntry, // increments ref
+ 0, xOffset, yOffset);
+ connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry);
+
+ mAllocator.releaseEventEntry(cancelationEventEntry);
+ }
+
+ if (!connection->outboundQueue.headSentinel.next->inProgress) {
+ startDispatchCycleLocked(currentTime, connection);
+ }
+ }
+}
+
InputDispatcher::MotionEntry*
InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) {
assert(pointerIds.value != 0);
@@ -1999,6 +2079,10 @@
return;
}
+ policyFlags |= POLICY_FLAG_TRUSTED;
+ mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
+ keyCode, scanCode, /*byref*/ policyFlags);
+
bool needWake;
{ // acquire lock
AutoMutex _l(mLock);
@@ -2041,6 +2125,9 @@
return;
}
+ policyFlags |= POLICY_FLAG_TRUSTED;
+ mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
+
bool needWake;
{ // acquire lock
AutoMutex _l(mLock);
@@ -2165,6 +2252,17 @@
}
}
+void InputDispatcher::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
+ uint32_t policyFlags) {
+#if DEBUG_INBOUND_EVENT_DETAILS
+ LOGD("notifySwitch - switchCode=%d, switchValue=%d, policyFlags=0x%x",
+ switchCode, switchValue, policyFlags);
+#endif
+
+ policyFlags |= POLICY_FLAG_TRUSTED;
+ mPolicy->notifySwitch(when, switchCode, switchValue, policyFlags);
+}
+
int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) {
#if DEBUG_INBOUND_EVENT_DETAILS
@@ -2175,26 +2273,81 @@
nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
- InjectionState* injectionState;
- bool needWake;
- { // acquire lock
- AutoMutex _l(mLock);
+ uint32_t policyFlags = POLICY_FLAG_INJECTED;
+ if (hasInjectionPermission(injectorPid, injectorUid)) {
+ policyFlags |= POLICY_FLAG_TRUSTED;
+ }
- EventEntry* injectedEntry = createEntryFromInjectedInputEventLocked(event);
- if (! injectedEntry) {
+ EventEntry* injectedEntry;
+ switch (event->getType()) {
+ case AINPUT_EVENT_TYPE_KEY: {
+ const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
+ int32_t action = keyEvent->getAction();
+ if (! validateKeyEvent(action)) {
return INPUT_EVENT_INJECTION_FAILED;
}
- injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid);
- if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
- injectionState->injectionIsAsync = true;
+ nsecs_t eventTime = keyEvent->getEventTime();
+ int32_t deviceId = keyEvent->getDeviceId();
+ int32_t flags = keyEvent->getFlags();
+ int32_t keyCode = keyEvent->getKeyCode();
+ int32_t scanCode = keyEvent->getScanCode();
+ mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
+ keyCode, scanCode, /*byref*/ policyFlags);
+
+ mLock.lock();
+ injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(),
+ policyFlags, action, flags, keyCode, scanCode, keyEvent->getMetaState(),
+ keyEvent->getRepeatCount(), keyEvent->getDownTime());
+ break;
+ }
+
+ case AINPUT_EVENT_TYPE_MOTION: {
+ const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
+ int32_t action = motionEvent->getAction();
+ size_t pointerCount = motionEvent->getPointerCount();
+ const int32_t* pointerIds = motionEvent->getPointerIds();
+ if (! validateMotionEvent(action, pointerCount, pointerIds)) {
+ return INPUT_EVENT_INJECTION_FAILED;
}
- injectionState->refCount += 1;
- injectedEntry->injectionState = injectionState;
+ nsecs_t eventTime = motionEvent->getEventTime();
+ mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
- needWake = enqueueInboundEventLocked(injectedEntry);
- } // release lock
+ mLock.lock();
+ const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
+ const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
+ MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes,
+ motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
+ action, motionEvent->getFlags(),
+ motionEvent->getMetaState(), motionEvent->getEdgeFlags(),
+ motionEvent->getXPrecision(), motionEvent->getYPrecision(),
+ motionEvent->getDownTime(), uint32_t(pointerCount),
+ pointerIds, samplePointerCoords);
+ for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
+ sampleEventTimes += 1;
+ samplePointerCoords += pointerCount;
+ mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords);
+ }
+ injectedEntry = motionEntry;
+ break;
+ }
+
+ default:
+ LOGW("Cannot inject event of type %d", event->getType());
+ return INPUT_EVENT_INJECTION_FAILED;
+ }
+
+ InjectionState* injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid);
+ if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
+ injectionState->injectionIsAsync = true;
+ }
+
+ injectionState->refCount += 1;
+ injectedEntry->injectionState = injectionState;
+
+ bool needWake = enqueueInboundEventLocked(injectedEntry);
+ mLock.unlock();
if (needWake) {
mLooper->wake();
@@ -2260,6 +2413,11 @@
return injectionResult;
}
+bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
+ return injectorUid == 0
+ || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
+}
+
void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) {
InjectionState* injectionState = entry->injectionState;
if (injectionState) {
@@ -2310,59 +2468,6 @@
}
}
-InputDispatcher::EventEntry* InputDispatcher::createEntryFromInjectedInputEventLocked(
- const InputEvent* event) {
- switch (event->getType()) {
- case AINPUT_EVENT_TYPE_KEY: {
- const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
- if (! validateKeyEvent(keyEvent->getAction())) {
- return NULL;
- }
-
- uint32_t policyFlags = POLICY_FLAG_INJECTED;
-
- KeyEntry* keyEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(),
- keyEvent->getDeviceId(), keyEvent->getSource(), policyFlags,
- keyEvent->getAction(), keyEvent->getFlags(),
- keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
- keyEvent->getRepeatCount(), keyEvent->getDownTime());
- return keyEntry;
- }
-
- case AINPUT_EVENT_TYPE_MOTION: {
- const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
- if (! validateMotionEvent(motionEvent->getAction(),
- motionEvent->getPointerCount(), motionEvent->getPointerIds())) {
- return NULL;
- }
-
- uint32_t policyFlags = POLICY_FLAG_INJECTED;
-
- const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
- const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
- size_t pointerCount = motionEvent->getPointerCount();
-
- MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes,
- motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
- motionEvent->getAction(), motionEvent->getFlags(),
- motionEvent->getMetaState(), motionEvent->getEdgeFlags(),
- motionEvent->getXPrecision(), motionEvent->getYPrecision(),
- motionEvent->getDownTime(), uint32_t(pointerCount),
- motionEvent->getPointerIds(), samplePointerCoords);
- for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
- sampleEventTimes += 1;
- samplePointerCoords += pointerCount;
- mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords);
- }
- return motionEntry;
- }
-
- default:
- assert(false);
- return NULL;
- }
-}
-
const InputWindow* InputDispatcher::getWindowLocked(const sp<InputChannel>& inputChannel) {
for (size_t i = 0; i < mWindows.size(); i++) {
const InputWindow* window = & mWindows[i];
@@ -2381,7 +2486,12 @@
AutoMutex _l(mLock);
// Clear old window pointers.
- mFocusedWindow = NULL;
+ sp<InputChannel> oldFocusedWindowChannel;
+ if (mFocusedWindow) {
+ oldFocusedWindowChannel = mFocusedWindow->inputChannel;
+ mFocusedWindow = NULL;
+ }
+
mWindows.clear();
// Loop over new windows and rebuild the necessary window pointers for
@@ -2397,6 +2507,24 @@
}
}
+ if (oldFocusedWindowChannel != NULL) {
+ if (!mFocusedWindow || oldFocusedWindowChannel != mFocusedWindow->inputChannel) {
+#if DEBUG_FOCUS
+ LOGD("Focus left window: %s",
+ oldFocusedWindowChannel->getName().string());
+#endif
+ synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel,
+ InputState::CANCEL_NON_POINTER_EVENTS, "focus left window");
+ oldFocusedWindowChannel.clear();
+ }
+ }
+ if (mFocusedWindow && oldFocusedWindowChannel == NULL) {
+#if DEBUG_FOCUS
+ LOGD("Focus entered window: %s",
+ mFocusedWindow->inputChannel->getName().string());
+#endif
+ }
+
for (size_t i = 0; i < mTouchState.windows.size(); ) {
TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
const InputWindow* window = getWindowLocked(touchedWindow.channel);
@@ -2404,12 +2532,17 @@
touchedWindow.window = window;
i += 1;
} else {
+#if DEBUG_FOCUS
+ LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string());
+#endif
mTouchState.windows.removeAt(i);
+ synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel,
+ InputState::CANCEL_POINTER_EVENTS, "touched window was removed");
}
}
#if DEBUG_FOCUS
- logDispatchStateLocked();
+ //logDispatchStateLocked();
#endif
} // release lock
@@ -2432,7 +2565,7 @@
}
#if DEBUG_FOCUS
- logDispatchStateLocked();
+ //logDispatchStateLocked();
#endif
} // release lock
@@ -2469,7 +2602,7 @@
}
#if DEBUG_FOCUS
- logDispatchStateLocked();
+ //logDispatchStateLocked();
#endif
} // release lock
@@ -2571,11 +2704,10 @@
for (size_t i = 0; i < mActiveConnections.size(); i++) {
const Connection* connection = mActiveConnections[i];
dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u"
- "inputState.isNeutral=%s, inputState.isOutOfSync=%s\n",
+ "inputState.isNeutral=%s\n",
i, connection->getInputChannelName(), connection->getStatusLabel(),
connection->outboundQueue.count(),
- toString(connection->inputState.isNeutral()),
- toString(connection->inputState.isOutOfSync()));
+ toString(connection->inputState.isNeutral()));
}
} else {
dump.append(INDENT "ActiveConnections: <none>\n");
@@ -2656,7 +2788,7 @@
mLooper->removeFd(inputChannel->getReceivePipeFd());
nsecs_t currentTime = now();
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
runCommandsLockedInterruptible();
} // release lock
@@ -2837,11 +2969,12 @@
}
void InputDispatcher::Allocator::initializeEventEntry(EventEntry* entry, int32_t type,
- nsecs_t eventTime) {
+ nsecs_t eventTime, uint32_t policyFlags) {
entry->type = type;
entry->refCount = 1;
entry->dispatchInProgress = false;
entry->eventTime = eventTime;
+ entry->policyFlags = policyFlags;
entry->injectionState = NULL;
}
@@ -2855,7 +2988,7 @@
InputDispatcher::ConfigurationChangedEntry*
InputDispatcher::Allocator::obtainConfigurationChangedEntry(nsecs_t eventTime) {
ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc();
- initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime);
+ initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime, 0);
return entry;
}
@@ -2864,11 +2997,10 @@
int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
int32_t repeatCount, nsecs_t downTime) {
KeyEntry* entry = mKeyEntryPool.alloc();
- initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime);
+ initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime, policyFlags);
entry->deviceId = deviceId;
entry->source = source;
- entry->policyFlags = policyFlags;
entry->action = action;
entry->flags = flags;
entry->keyCode = keyCode;
@@ -2887,12 +3019,11 @@
nsecs_t downTime, uint32_t pointerCount,
const int32_t* pointerIds, const PointerCoords* pointerCoords) {
MotionEntry* entry = mMotionEntryPool.alloc();
- initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime);
+ initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime, policyFlags);
entry->eventTime = eventTime;
entry->deviceId = deviceId;
entry->source = source;
- entry->policyFlags = policyFlags;
entry->action = action;
entry->flags = flags;
entry->metaState = metaState;
@@ -3039,8 +3170,7 @@
// --- InputDispatcher::InputState ---
-InputDispatcher::InputState::InputState() :
- mIsOutOfSync(false) {
+InputDispatcher::InputState::InputState() {
}
InputDispatcher::InputState::~InputState() {
@@ -3050,20 +3180,6 @@
return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
}
-bool InputDispatcher::InputState::isOutOfSync() const {
- return mIsOutOfSync;
-}
-
-void InputDispatcher::InputState::setOutOfSync() {
- if (! isNeutral()) {
- mIsOutOfSync = true;
- }
-}
-
-void InputDispatcher::InputState::resetOutOfSync() {
- mIsOutOfSync = false;
-}
-
InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackEvent(
const EventEntry* entry) {
switch (entry->type) {
@@ -3090,9 +3206,6 @@
switch (action) {
case AKEY_EVENT_ACTION_UP:
mKeyMementos.removeAt(i);
- if (isNeutral()) {
- mIsOutOfSync = false;
- }
return CONSISTENT;
case AKEY_EVENT_ACTION_DOWN:
@@ -3132,9 +3245,6 @@
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
mMotionMementos.removeAt(i);
- if (isNeutral()) {
- mIsOutOfSync = false;
- }
return CONSISTENT;
case AMOTION_EVENT_ACTION_DOWN:
@@ -3192,30 +3302,52 @@
}
}
-void InputDispatcher::InputState::synthesizeCancelationEvents(
- Allocator* allocator, Vector<EventEntry*>& outEvents) const {
- for (size_t i = 0; i < mKeyMementos.size(); i++) {
+void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
+ Allocator* allocator, Vector<EventEntry*>& outEvents,
+ CancelationOptions options) {
+ for (size_t i = 0; i < mKeyMementos.size(); ) {
const KeyMemento& memento = mKeyMementos.itemAt(i);
- outEvents.push(allocator->obtainKeyEntry(now(),
- memento.deviceId, memento.source, 0,
- AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED,
- memento.keyCode, memento.scanCode, 0, 0, memento.downTime));
+ if (shouldCancelEvent(memento.source, options)) {
+ outEvents.push(allocator->obtainKeyEntry(currentTime,
+ memento.deviceId, memento.source, 0,
+ AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED,
+ memento.keyCode, memento.scanCode, 0, 0, memento.downTime));
+ mKeyMementos.removeAt(i);
+ } else {
+ i += 1;
+ }
}
- for (size_t i = 0; i < mMotionMementos.size(); i++) {
+ for (size_t i = 0; i < mMotionMementos.size(); ) {
const MotionMemento& memento = mMotionMementos.itemAt(i);
- outEvents.push(allocator->obtainMotionEntry(now(),
- memento.deviceId, memento.source, 0,
- AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0,
- memento.xPrecision, memento.yPrecision, memento.downTime,
- memento.pointerCount, memento.pointerIds, memento.pointerCoords));
+ if (shouldCancelEvent(memento.source, options)) {
+ outEvents.push(allocator->obtainMotionEntry(currentTime,
+ memento.deviceId, memento.source, 0,
+ AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0,
+ memento.xPrecision, memento.yPrecision, memento.downTime,
+ memento.pointerCount, memento.pointerIds, memento.pointerCoords));
+ mMotionMementos.removeAt(i);
+ } else {
+ i += 1;
+ }
}
}
void InputDispatcher::InputState::clear() {
mKeyMementos.clear();
mMotionMementos.clear();
- mIsOutOfSync = false;
+}
+
+bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource,
+ CancelationOptions options) {
+ switch (options) {
+ case CANCEL_POINTER_EVENTS:
+ return eventSource & AINPUT_SOURCE_CLASS_POINTER;
+ case CANCEL_NON_POINTER_EVENTS:
+ return !(eventSource & AINPUT_SOURCE_CLASS_POINTER);
+ default:
+ return true;
+ }
}
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 8e173aa..0560bb8 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -796,10 +796,6 @@
return 0;
}
-bool InputMapper::applyStandardPolicyActions(nsecs_t when, int32_t policyActions) {
- return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
-}
-
// --- SwitchInputMapper ---
@@ -823,11 +819,7 @@
}
void SwitchInputMapper::processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) {
- uint32_t policyFlags = 0;
- int32_t policyActions = getPolicy()->interceptSwitch(
- when, switchCode, switchValue, policyFlags);
-
- applyStandardPolicyActions(when, policyActions);
+ getDispatcher()->notifySwitch(when, switchCode, switchValue, 0);
}
int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
@@ -983,29 +975,9 @@
getContext()->updateGlobalMetaState();
}
- applyPolicyAndDispatch(when, policyFlags, down, keyCode, scanCode, newMetaState, downTime);
-}
-
-void KeyboardInputMapper::applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, bool down,
- int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {
- int32_t policyActions = getPolicy()->interceptKey(when,
- getDeviceId(), down, keyCode, scanCode, policyFlags);
-
- if (! applyStandardPolicyActions(when, policyActions)) {
- return; // event dropped
- }
-
- int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP;
- int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
- if (policyFlags & POLICY_FLAG_WOKE_HERE) {
- keyEventFlags |= AKEY_EVENT_FLAG_WOKE_HERE;
- }
- if (policyFlags & POLICY_FLAG_VIRTUAL) {
- keyEventFlags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
- }
-
getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
- keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
+ down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
+ AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
}
ssize_t KeyboardInputMapper::findKeyDownLocked(int32_t scanCode) {
@@ -1215,26 +1187,13 @@
}
} // release lock
- applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime);
-
- mAccumulator.clear();
-}
-
-void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
- PointerCoords* pointerCoords, nsecs_t downTime) {
- uint32_t policyFlags = 0;
- int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
-
- if (! applyStandardPolicyActions(when, policyActions)) {
- return; // event dropped
- }
-
int32_t metaState = mContext->getGlobalMetaState();
int32_t pointerId = 0;
-
- getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags,
+ getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, 0,
motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
- 1, & pointerId, pointerCoords, mXPrecision, mYPrecision, downTime);
+ 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
+
+ mAccumulator.clear();
}
int32_t TrackballInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
@@ -2012,15 +1971,7 @@
}
void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
- // Apply generic policy actions.
-
uint32_t policyFlags = 0;
- int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
-
- if (! applyStandardPolicyActions(when, policyActions)) {
- mLastTouch.clear();
- return; // event dropped
- }
// Preprocess pointer data.
@@ -2160,24 +2111,11 @@
} // release lock
// Dispatch virtual key.
- applyPolicyAndDispatchVirtualKey(when, policyFlags, keyEventAction, keyEventFlags,
- keyCode, scanCode, downTime);
- return touchResult;
-}
-
-void TouchInputMapper::applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
- int32_t keyEventAction, int32_t keyEventFlags,
- int32_t keyCode, int32_t scanCode, nsecs_t downTime) {
int32_t metaState = mContext->getGlobalMetaState();
-
policyFlags |= POLICY_FLAG_VIRTUAL;
- int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(),
- keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
-
- if (applyStandardPolicyActions(when, policyActions)) {
- getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
- keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
- }
+ getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
+ keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
+ return touchResult;
}
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
@@ -2447,7 +2385,7 @@
yPrecision = mLocked.orientedYPrecision;
} // release lock
- getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
+ getDispatcher()->notifyMotion(when, getDeviceId(), getSources(), policyFlags,
motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
pointerCount, pointerIds, pointerCoords,
xPrecision, yPrecision, mDownTime);
diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp
index e170ab8..2c3724c 100644
--- a/libs/utils/ObbFile.cpp
+++ b/libs/utils/ObbFile.cpp
@@ -29,10 +29,11 @@
#define kFooterTagSize 8 /* last two 32-bit integers */
-#define kFooterMinSize 25 /* 32-bit signature version (4 bytes)
+#define kFooterMinSize 33 /* 32-bit signature version (4 bytes)
* 32-bit package version (4 bytes)
* 32-bit flags (4 bytes)
- * 32-bit package name size (4-bytes)
+ * 64-bit salt (8 bytes)
+ * 32-bit package name size (4 bytes)
* >=1-character package name (1 byte)
* 32-bit footer size (4 bytes)
* 32-bit footer marker (4 bytes)
@@ -47,8 +48,9 @@
/* offsets in version 1 of the header */
#define kPackageVersionOffset 4
#define kFlagsOffset 8
-#define kPackageNameLenOffset 12
-#define kPackageNameOffset 16
+#define kSaltOffset 12
+#define kPackageNameLenOffset 20
+#define kPackageNameOffset 24
/*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of
@@ -79,11 +81,12 @@
namespace android {
-ObbFile::ObbFile() :
- mPackageName(""),
- mVersion(-1),
- mFlags(0)
+ObbFile::ObbFile()
+ : mPackageName("")
+ , mVersion(-1)
+ , mFlags(0)
{
+ memset(mSalt, 0, sizeof(mSalt));
}
ObbFile::~ObbFile() {
@@ -192,7 +195,7 @@
#ifdef DEBUG
for (int i = 0; i < footerSize; ++i) {
- LOGI("char: 0x%02x", scanBuf[i]);
+ LOGI("char: 0x%02x\n", scanBuf[i]);
}
#endif
@@ -206,6 +209,8 @@
mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset);
+ memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt));
+
uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
if (packageNameLen <= 0
|| packageNameLen > (footerSize - kPackageNameOffset)) {
@@ -255,7 +260,7 @@
my_lseek64(fd, 0, SEEK_END);
if (mPackageName.size() == 0 || mVersion == -1) {
- LOGW("tried to write uninitialized ObbFile data");
+ LOGW("tried to write uninitialized ObbFile data\n");
return false;
}
@@ -264,43 +269,48 @@
put4LE(intBuf, kSigVersion);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write signature version: %s", strerror(errno));
+ LOGW("couldn't write signature version: %s\n", strerror(errno));
return false;
}
put4LE(intBuf, mVersion);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write package version");
+ LOGW("couldn't write package version\n");
return false;
}
put4LE(intBuf, mFlags);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write package version");
+ LOGW("couldn't write package version\n");
+ return false;
+ }
+
+ if (write(fd, mSalt, sizeof(mSalt)) != (ssize_t)sizeof(mSalt)) {
+ LOGW("couldn't write salt: %s\n", strerror(errno));
return false;
}
size_t packageNameLen = mPackageName.size();
put4LE(intBuf, packageNameLen);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write package name length: %s", strerror(errno));
+ LOGW("couldn't write package name length: %s\n", strerror(errno));
return false;
}
if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
- LOGW("couldn't write package name: %s", strerror(errno));
+ LOGW("couldn't write package name: %s\n", strerror(errno));
return false;
}
put4LE(intBuf, kPackageNameOffset + packageNameLen);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write footer size: %s", strerror(errno));
+ LOGW("couldn't write footer size: %s\n", strerror(errno));
return false;
}
put4LE(intBuf, kSignature);
if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
- LOGW("couldn't write footer magic signature: %s", strerror(errno));
+ LOGW("couldn't write footer magic signature: %s\n", strerror(errno));
return false;
}
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index 9b1f82f..5ff1f8f 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -32,6 +32,22 @@
#include <assert.h>
#include <unistd.h>
+#if HAVE_PRINTF_ZD
+# define ZD "%zd"
+# define ZD_TYPE ssize_t
+#else
+# define ZD "%ld"
+# define ZD_TYPE long
+#endif
+
+/*
+ * We must open binary files using open(path, ... | O_BINARY) under Windows.
+ * Otherwise strange read errors will happen.
+ */
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
/*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of
* <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
@@ -124,7 +140,7 @@
/*
* Open and map the specified file.
*/
- fd = ::open(zipFileName, O_RDONLY);
+ fd = ::open(zipFileName, O_RDONLY | O_BINARY);
if (fd < 0) {
LOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno));
return NAME_NOT_FOUND;
@@ -172,8 +188,8 @@
*/
bool ZipFileRO::mapCentralDirectory(void)
{
- size_t readAmount = kMaxEOCDSearch;
- if (readAmount > (size_t) mFileLength)
+ ssize_t readAmount = kMaxEOCDSearch;
+ if (readAmount > (ssize_t) mFileLength)
readAmount = mFileLength;
unsigned char* scanBuf = (unsigned char*) malloc(readAmount);
@@ -233,7 +249,8 @@
}
actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, readAmount));
if (actual != (ssize_t) readAmount) {
- LOGW("Zip: read %zd failed: %s\n", readAmount, strerror(errno));
+ LOGW("Zip: read " ZD ", expected " ZD ". Failed: %s\n",
+ (ZD_TYPE) actual, (ZD_TYPE) readAmount, strerror(errno));
free(scanBuf);
return false;
}
@@ -292,8 +309,8 @@
}
if (!mDirectoryMap->create(mFileName, mFd, dirOffset, dirSize, true)) {
- LOGW("Unable to map '%s' (%zd to %zd): %s\n", mFileName,
- dirOffset, dirOffset + dirSize, strerror(errno));
+ LOGW("Unable to map '%s' (" ZD " to " ZD "): %s\n", mFileName,
+ (ZD_TYPE) dirOffset, (ZD_TYPE) (dirOffset + dirSize), strerror(errno));
return false;
}
@@ -350,8 +367,8 @@
ptr += kCDELen + fileNameLen + extraLen + commentLen;
if ((size_t)(ptr - cdPtr) > cdLength) {
- LOGW("bad CD advance (%d vs %zd) at entry %d\n",
- (int) (ptr - cdPtr), cdLength, i);
+ LOGW("bad CD advance (%d vs " ZD ") at entry %d\n",
+ (int) (ptr - cdPtr), (ZD_TYPE) cdLength, i);
goto bail;
}
}
@@ -556,8 +573,8 @@
if (get4LE(lfhBuf) != kLFHSignature) {
off_t actualOffset = lseek(mFd, 0, SEEK_CUR);
LOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; "
- "got: offset=%zd data=0x%08lx\n",
- localHdrOffset, kLFHSignature, (size_t)actualOffset, get4LE(lfhBuf));
+ "got: offset=" ZD " data=0x%08lx\n",
+ localHdrOffset, kLFHSignature, (ZD_TYPE) actualOffset, get4LE(lfhBuf));
return false;
}
}
@@ -572,16 +589,16 @@
/* check lengths */
if ((off_t)(dataOffset + compLen) > cdOffset) {
- LOGW("bad compressed length in zip (%ld + %zd > %ld)\n",
- (long) dataOffset, compLen, (long) cdOffset);
+ LOGW("bad compressed length in zip (%ld + " ZD " > %ld)\n",
+ (long) dataOffset, (ZD_TYPE) compLen, (long) cdOffset);
return false;
}
if (method == kCompressStored &&
(off_t)(dataOffset + uncompLen) > cdOffset)
{
- LOGE("ERROR: bad uncompressed length in zip (%ld + %zd > %ld)\n",
- (long) dataOffset, uncompLen, (long) cdOffset);
+ LOGE("ERROR: bad uncompressed length in zip (%ld + " ZD " > %ld)\n",
+ (long) dataOffset, (ZD_TYPE) uncompLen, (long) cdOffset);
return false;
}
@@ -732,8 +749,8 @@
LOGE("Write failed: %s\n", strerror(errno));
goto unmap;
} else if ((size_t) actual != uncompLen) {
- LOGE("Partial write during uncompress (%zd of %zd)\n",
- (size_t)actual, (size_t)uncompLen);
+ LOGE("Partial write during uncompress (" ZD " of " ZD ")\n",
+ (ZD_TYPE) actual, (ZD_TYPE) uncompLen);
goto unmap;
} else {
LOGI("+++ successful write\n");
@@ -802,8 +819,8 @@
/* paranoia */
if (zstream.total_out != uncompLen) {
- LOGW("Size mismatch on inflated file (%ld vs %zd)\n",
- zstream.total_out, uncompLen);
+ LOGW("Size mismatch on inflated file (%ld vs " ZD ")\n",
+ zstream.total_out, (ZD_TYPE) uncompLen);
goto z_bail;
}
@@ -891,8 +908,8 @@
/* paranoia */
if (zstream.total_out != uncompLen) {
- LOGW("Size mismatch on inflated file (%ld vs %zd)\n",
- zstream.total_out, uncompLen);
+ LOGW("Size mismatch on inflated file (%ld vs " ZD ")\n",
+ zstream.total_out, (ZD_TYPE) uncompLen);
goto z_bail;
}
diff --git a/libs/utils/tests/ObbFile_test.cpp b/libs/utils/tests/ObbFile_test.cpp
index 29bb70a..46b30c2 100644
--- a/libs/utils/tests/ObbFile_test.cpp
+++ b/libs/utils/tests/ObbFile_test.cpp
@@ -23,6 +23,7 @@
#include <gtest/gtest.h>
#include <fcntl.h>
+#include <string.h>
namespace android {
@@ -63,6 +64,10 @@
mObbFile->setPackageName(String8(packageName));
mObbFile->setVersion(versionNum);
+#define SALT_SIZE 8
+ unsigned char salt[SALT_SIZE] = {0x01, 0x10, 0x55, 0xAA, 0xFF, 0x00, 0x5A, 0xA5};
+ EXPECT_TRUE(mObbFile->setSalt(salt, SALT_SIZE))
+ << "Salt should be successfully set";
EXPECT_TRUE(mObbFile->writeTo(mFileName))
<< "couldn't write to fake .obb file";
@@ -77,6 +82,19 @@
const char* currentPackageName = mObbFile->getPackageName().string();
EXPECT_STREQ(packageName, currentPackageName)
<< "package name didn't come out the same as it went in";
+
+ size_t saltLen;
+ const unsigned char* newSalt = mObbFile->getSalt(&saltLen);
+
+ EXPECT_EQ(sizeof(salt), saltLen)
+ << "salt sizes were not the same";
+
+ for (int i = 0; i < sizeof(salt); i++) {
+ EXPECT_EQ(salt[i], newSalt[i])
+ << "salt character " << i << " should be equal";
+ }
+ EXPECT_TRUE(memcmp(newSalt, salt, sizeof(salt)) == 0)
+ << "salts should be the same";
}
}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index 1d09f84..90865da 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -359,7 +359,7 @@
DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
uint32_t displayIndex)
- : mCanDraw(true)
+ : mCanDraw(true), mScreenAcquired(true)
{
mDisplayEventThread = new DisplayEventThread(flinger);
if (mDisplayEventThread->initCheck() != NO_ERROR) {
@@ -374,18 +374,21 @@
mDisplayEventThread->requestExitAndWait();
}
+void DisplayHardwareBase::setCanDraw(bool canDraw)
+{
+ mCanDraw = canDraw;
+}
bool DisplayHardwareBase::canDraw() const
{
- return mCanDraw;
+ return mCanDraw && mScreenAcquired;
}
void DisplayHardwareBase::releaseScreen() const
{
status_t err = mDisplayEventThread->releaseScreen();
if (err >= 0) {
- //LOGD("screen given-up");
- mCanDraw = false;
+ mScreenAcquired = false;
}
}
@@ -393,9 +396,13 @@
{
status_t err = mDisplayEventThread->acquireScreen();
if (err >= 0) {
- //LOGD("screen returned");
- mCanDraw = true;
+ mScreenAcquired = true;
}
}
+bool DisplayHardwareBase::isScreenAcquired() const
+{
+ return mScreenAcquired;
+}
+
}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index 8369bb8..fa6a0c4 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -40,7 +40,11 @@
// console managment
void releaseScreen() const;
void acquireScreen() const;
+ bool isScreenAcquired() const;
+
bool canDraw() const;
+ void setCanDraw(bool canDraw);
+
private:
class DisplayEventThreadBase : public Thread {
@@ -89,6 +93,7 @@
sp<DisplayEventThreadBase> mDisplayEventThread;
mutable int mCanDraw;
+ mutable int mScreenAcquired;
};
}; // namespace android
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 758b408..069b85a 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -444,11 +444,11 @@
}
if (transform & HAL_TRANSFORM_FLIP_V) {
swap(vLT, vLB);
- swap(vRB, vRT);
+ swap(vRT, vRB);
}
if (transform & HAL_TRANSFORM_FLIP_H) {
- swap(vLT, vRB);
- swap(vLB, vRT);
+ swap(vLT, vRT);
+ swap(vLB, vRB);
}
TexCoords texCoords[4];
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index d668e88..aebe1b8 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -72,14 +72,6 @@
nsecs_t now = systemTime();
nsecs_t nextEventTime = -1;
- // invalidate messages are always handled first
- if (mInvalidate) {
- mInvalidate = false;
- mInvalidateMessage->when = now;
- result = mInvalidateMessage;
- break;
- }
-
LIST::iterator cur(mMessages.begin());
if (cur != mMessages.end()) {
result = *cur;
@@ -91,17 +83,29 @@
mMessages.remove(cur);
break;
}
- if (timeout>=0 && timeoutTime < now) {
- // we timed-out, return a NULL message
- result = 0;
- break;
- }
nextEventTime = result->when;
result = 0;
}
- if (timeout >= 0 && nextEventTime > 0) {
- if (nextEventTime > timeoutTime) {
+ // see if we have an invalidate message
+ if (mInvalidate) {
+ mInvalidate = false;
+ mInvalidateMessage->when = now;
+ result = mInvalidateMessage;
+ break;
+ }
+
+ if (timeout >= 0) {
+ if (timeoutTime < now) {
+ // we timed-out, return a NULL message
+ result = 0;
+ break;
+ }
+ if (nextEventTime > 0) {
+ if (nextEventTime > timeoutTime) {
+ nextEventTime = timeoutTime;
+ }
+ } else {
nextEventTime = timeoutTime;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e5e87c6..a9b3965 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -80,6 +80,7 @@
mVisibleRegionsDirty(false),
mDeferReleaseConsole(false),
mFreezeDisplay(false),
+ mElectronBeamAnimationMode(0),
mFreezeCount(0),
mFreezeDisplayTime(0),
mDebugRegion(0),
@@ -421,16 +422,19 @@
int what = android_atomic_and(0, &mConsoleSignals);
if (what & eConsoleAcquired) {
hw.acquireScreen();
+ // this is a temporary work-around, eventually this should be called
+ // by the power-manager
+ SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode);
}
- if (mDeferReleaseConsole && hw.canDraw()) {
+ if (mDeferReleaseConsole && hw.isScreenAcquired()) {
// We got the release signal before the acquire signal
mDeferReleaseConsole = false;
hw.releaseScreen();
}
if (what & eConsoleReleased) {
- if (hw.canDraw()) {
+ if (hw.isScreenAcquired()) {
hw.releaseScreen();
} else {
mDeferReleaseConsole = true;
@@ -1456,6 +1460,8 @@
case FREEZE_DISPLAY:
case UNFREEZE_DISPLAY:
case BOOT_FINISHED:
+ case TURN_ELECTRON_BEAM_OFF:
+ case TURN_ELECTRON_BEAM_ON:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
@@ -1546,6 +1552,457 @@
// ---------------------------------------------------------------------------
+status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy,
+ GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
+{
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+ // get screen geometry
+ const DisplayHardware& hw(graphicPlane(dpy).displayHardware());
+ const uint32_t hw_w = hw.getWidth();
+ const uint32_t hw_h = hw.getHeight();
+ GLfloat u = 1;
+ GLfloat v = 1;
+
+ // make sure to clear all GL error flags
+ while ( glGetError() != GL_NO_ERROR ) ;
+
+ // create a FBO
+ GLuint name, tname;
+ glGenTextures(1, &tname);
+ glBindTexture(GL_TEXTURE_2D, tname);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+ if (glGetError() != GL_NO_ERROR) {
+ while ( glGetError() != GL_NO_ERROR ) ;
+ GLint tw = (2 << (31 - clz(hw_w)));
+ GLint th = (2 << (31 - clz(hw_h)));
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+ u = GLfloat(hw_w) / tw;
+ v = GLfloat(hw_h) / th;
+ }
+ glGenFramebuffersOES(1, &name);
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
+ glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
+ GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
+
+ // redraw the screen entirely...
+ glClearColor(0,0,0,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<LayerBase>& layer(layers[i]);
+ layer->drawForSreenShot();
+ }
+
+ // back to main framebuffer
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+ glDisable(GL_SCISSOR_TEST);
+ glDeleteFramebuffersOES(1, &name);
+
+ *textureName = tname;
+ *uOut = u;
+ *vOut = v;
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
+{
+ status_t result = PERMISSION_DENIED;
+
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+ // get screen geometry
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t hw_w = hw.getWidth();
+ const uint32_t hw_h = hw.getHeight();
+ const Region screenBounds(hw.bounds());
+
+ GLfloat u, v;
+ GLuint tname;
+ result = renderScreenToTextureLocked(0, &tname, &u, &v);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ GLfloat vtx[8];
+ const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, tname);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vtx);
+
+ class s_curve_interpolator {
+ const float nbFrames, s, v;
+ public:
+ s_curve_interpolator(int nbFrames, float s)
+ : nbFrames(1.0f / (nbFrames-1)), s(s),
+ v(1.0f + expf(-s + 0.5f*s)) {
+ }
+ float operator()(int f) {
+ const float x = f * nbFrames;
+ return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f;
+ }
+ };
+
+ class v_stretch {
+ const GLfloat hw_w, hw_h;
+ public:
+ v_stretch(uint32_t hw_w, uint32_t hw_h)
+ : hw_w(hw_w), hw_h(hw_h) {
+ }
+ void operator()(GLfloat* vtx, float v) {
+ const GLfloat w = hw_w + (hw_w * v);
+ const GLfloat h = hw_h - (hw_h * v);
+ const GLfloat x = (hw_w - w) * 0.5f;
+ const GLfloat y = (hw_h - h) * 0.5f;
+ vtx[0] = x; vtx[1] = y;
+ vtx[2] = x; vtx[3] = y + h;
+ vtx[4] = x + w; vtx[5] = y + h;
+ vtx[6] = x + w; vtx[7] = y;
+ }
+ };
+
+ class h_stretch {
+ const GLfloat hw_w, hw_h;
+ public:
+ h_stretch(uint32_t hw_w, uint32_t hw_h)
+ : hw_w(hw_w), hw_h(hw_h) {
+ }
+ void operator()(GLfloat* vtx, float v) {
+ const GLfloat w = hw_w - (hw_w * v);
+ const GLfloat h = 1.0f;
+ const GLfloat x = (hw_w - w) * 0.5f;
+ const GLfloat y = (hw_h - h) * 0.5f;
+ vtx[0] = x; vtx[1] = y;
+ vtx[2] = x; vtx[3] = y + h;
+ vtx[4] = x + w; vtx[5] = y + h;
+ vtx[6] = x + w; vtx[7] = y;
+ }
+ };
+
+ // the full animation is 24 frames
+ const int nbFrames = 12;
+ s_curve_interpolator itr(nbFrames, 7.5f);
+ s_curve_interpolator itg(nbFrames, 8.0f);
+ s_curve_interpolator itb(nbFrames, 8.5f);
+
+ v_stretch vverts(hw_w, hw_h);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+ for (int i=0 ; i<nbFrames ; i++) {
+ float x, y, w, h;
+ const float vr = itr(i);
+ const float vg = itg(i);
+ const float vb = itb(i);
+
+ // clear screen
+ glColorMask(1,1,1,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glEnable(GL_TEXTURE_2D);
+
+ // draw the red plane
+ vverts(vtx, vr);
+ glColorMask(1,0,0,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // draw the green plane
+ vverts(vtx, vg);
+ glColorMask(0,1,0,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // draw the blue plane
+ vverts(vtx, vb);
+ glColorMask(0,0,1,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // draw the white highlight (we use the last vertices)
+ glDisable(GL_TEXTURE_2D);
+ glColorMask(1,1,1,1);
+ glColor4f(vg, vg, vg, 1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ hw.flip(screenBounds);
+ }
+
+ h_stretch hverts(hw_w, hw_h);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ glColorMask(1,1,1,1);
+ for (int i=0 ; i<nbFrames ; i++) {
+ const float v = itg(i);
+ hverts(vtx, v);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor4f(1-v, 1-v, 1-v, 1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ hw.flip(screenBounds);
+ }
+
+ glColorMask(1,1,1,1);
+ glEnable(GL_SCISSOR_TEST);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDeleteTextures(1, &tname);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::electronBeamOnAnimationImplLocked()
+{
+ status_t result = PERMISSION_DENIED;
+
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+
+ // get screen geometry
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t hw_w = hw.getWidth();
+ const uint32_t hw_h = hw.getHeight();
+ const Region screenBounds(hw.bounds());
+
+ GLfloat u, v;
+ GLuint tname;
+ result = renderScreenToTextureLocked(0, &tname, &u, &v);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ // back to main framebuffer
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+ glDisable(GL_SCISSOR_TEST);
+
+ GLfloat vtx[8];
+ const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, tname);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vtx);
+
+ class s_curve_interpolator {
+ const float nbFrames, s, v;
+ public:
+ s_curve_interpolator(int nbFrames, float s)
+ : nbFrames(1.0f / (nbFrames-1)), s(s),
+ v(1.0f + expf(-s + 0.5f*s)) {
+ }
+ float operator()(int f) {
+ const float x = f * nbFrames;
+ return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f;
+ }
+ };
+
+ class v_stretch {
+ const GLfloat hw_w, hw_h;
+ public:
+ v_stretch(uint32_t hw_w, uint32_t hw_h)
+ : hw_w(hw_w), hw_h(hw_h) {
+ }
+ void operator()(GLfloat* vtx, float v) {
+ const GLfloat w = hw_w + (hw_w * v);
+ const GLfloat h = hw_h - (hw_h * v);
+ const GLfloat x = (hw_w - w) * 0.5f;
+ const GLfloat y = (hw_h - h) * 0.5f;
+ vtx[0] = x; vtx[1] = y;
+ vtx[2] = x; vtx[3] = y + h;
+ vtx[4] = x + w; vtx[5] = y + h;
+ vtx[6] = x + w; vtx[7] = y;
+ }
+ };
+
+ class h_stretch {
+ const GLfloat hw_w, hw_h;
+ public:
+ h_stretch(uint32_t hw_w, uint32_t hw_h)
+ : hw_w(hw_w), hw_h(hw_h) {
+ }
+ void operator()(GLfloat* vtx, float v) {
+ const GLfloat w = hw_w - (hw_w * v);
+ const GLfloat h = 1.0f;
+ const GLfloat x = (hw_w - w) * 0.5f;
+ const GLfloat y = (hw_h - h) * 0.5f;
+ vtx[0] = x; vtx[1] = y;
+ vtx[2] = x; vtx[3] = y + h;
+ vtx[4] = x + w; vtx[5] = y + h;
+ vtx[6] = x + w; vtx[7] = y;
+ }
+ };
+
+ // the full animation is 12 frames
+ int nbFrames = 8;
+ s_curve_interpolator itr(nbFrames, 7.5f);
+ s_curve_interpolator itg(nbFrames, 8.0f);
+ s_curve_interpolator itb(nbFrames, 8.5f);
+
+ h_stretch hverts(hw_w, hw_h);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ glColorMask(1,1,1,1);
+ for (int i=nbFrames-1 ; i>=0 ; i--) {
+ const float v = itg(i);
+ hverts(vtx, v);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor4f(1-v, 1-v, 1-v, 1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ hw.flip(screenBounds);
+ }
+
+ nbFrames = 4;
+ v_stretch vverts(hw_w, hw_h);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+ for (int i=nbFrames-1 ; i>=0 ; i--) {
+ float x, y, w, h;
+ const float vr = itr(i);
+ const float vg = itg(i);
+ const float vb = itb(i);
+
+ // clear screen
+ glColorMask(1,1,1,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glEnable(GL_TEXTURE_2D);
+
+ // draw the red plane
+ vverts(vtx, vr);
+ glColorMask(1,0,0,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // draw the green plane
+ vverts(vtx, vg);
+ glColorMask(0,1,0,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // draw the blue plane
+ vverts(vtx, vb);
+ glColorMask(0,0,1,1);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ hw.flip(screenBounds);
+ }
+
+ glColorMask(1,1,1,1);
+ glEnable(GL_SCISSOR_TEST);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDeleteTextures(1, &tname);
+
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::turnElectronBeamOffImplLocked(int32_t mode)
+{
+ DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
+ if (!hw.canDraw()) {
+ // we're already off
+ return NO_ERROR;
+ }
+ if (mode & ISurfaceComposer::eElectronBeamAnimationOff) {
+ electronBeamOffAnimationImplLocked();
+ }
+
+ // always clear the whole screen at the end of the animation
+ glClearColor(0,0,0,1);
+ glDisable(GL_SCISSOR_TEST);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glEnable(GL_SCISSOR_TEST);
+ hw.flip( Region(hw.bounds()) );
+
+ hw.setCanDraw(false);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::turnElectronBeamOff(int32_t mode)
+{
+ class MessageTurnElectronBeamOff : public MessageBase {
+ SurfaceFlinger* flinger;
+ int32_t mode;
+ status_t result;
+ public:
+ MessageTurnElectronBeamOff(SurfaceFlinger* flinger, int32_t mode)
+ : flinger(flinger), mode(mode), result(PERMISSION_DENIED) {
+ }
+ status_t getResult() const {
+ return result;
+ }
+ virtual bool handler() {
+ Mutex::Autolock _l(flinger->mStateLock);
+ result = flinger->turnElectronBeamOffImplLocked(mode);
+ return true;
+ }
+ };
+
+ sp<MessageBase> msg = new MessageTurnElectronBeamOff(this, mode);
+ status_t res = postMessageSync(msg);
+ if (res == NO_ERROR) {
+ res = static_cast<MessageTurnElectronBeamOff*>( msg.get() )->getResult();
+
+ // work-around: when the power-manager calls us we activate the
+ // animation. eventually, the "on" animation will be called
+ // by the power-manager itself
+ mElectronBeamAnimationMode = mode;
+ }
+ return res;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::turnElectronBeamOnImplLocked(int32_t mode)
+{
+ DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
+ if (hw.canDraw()) {
+ // we're already on
+ return NO_ERROR;
+ }
+ if (mode & ISurfaceComposer::eElectronBeamAnimationOn) {
+ electronBeamOnAnimationImplLocked();
+ }
+ hw.setCanDraw(true);
+
+ // make sure to redraw the whole screen when the animation is done
+ mDirtyRegion.set(hw.bounds());
+ signalEvent();
+
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::turnElectronBeamOn(int32_t mode)
+{
+ class MessageTurnElectronBeamOn : public MessageBase {
+ SurfaceFlinger* flinger;
+ int32_t mode;
+ status_t result;
+ public:
+ MessageTurnElectronBeamOn(SurfaceFlinger* flinger, int32_t mode)
+ : flinger(flinger), mode(mode), result(PERMISSION_DENIED) {
+ }
+ status_t getResult() const {
+ return result;
+ }
+ virtual bool handler() {
+ Mutex::Autolock _l(flinger->mStateLock);
+ result = flinger->turnElectronBeamOnImplLocked(mode);
+ return true;
+ }
+ };
+
+ postMessageAsync( new MessageTurnElectronBeamOn(this, mode) );
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
sp<IMemoryHeap>* heap,
uint32_t* w, uint32_t* h, PixelFormat* f,
@@ -2005,6 +2462,10 @@
return *mHw;
}
+DisplayHardware& GraphicPlane::editDisplayHardware() {
+ return *mHw;
+}
+
const Transform& GraphicPlane::transform() const {
return mGlobalTransform;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f0a167b..4262175 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -141,6 +141,7 @@
int getHeight() const;
const DisplayHardware& displayHardware() const;
+ DisplayHardware& editDisplayHardware();
const Transform& transform() const;
EGLDisplay getEGLDisplay() const;
@@ -200,6 +201,8 @@
PixelFormat* format,
uint32_t reqWidth,
uint32_t reqHeight);
+ virtual status_t turnElectronBeamOff(int32_t mode);
+ virtual status_t turnElectronBeamOn(int32_t mode);
void screenReleased(DisplayID dpy);
void screenAcquired(DisplayID dpy);
@@ -325,6 +328,13 @@
uint32_t* width, uint32_t* height, PixelFormat* format,
uint32_t reqWidth = 0, uint32_t reqHeight = 0);
+ status_t turnElectronBeamOffImplLocked(int32_t mode);
+ status_t turnElectronBeamOnImplLocked(int32_t mode);
+ status_t electronBeamOffAnimationImplLocked();
+ status_t electronBeamOnAnimationImplLocked();
+ status_t renderScreenToTextureLocked(DisplayID dpy,
+ GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
+
friend class FreezeLock;
sp<FreezeLock> getFreezeLock() const;
inline void incFreezeCount() {
@@ -385,6 +395,7 @@
bool mVisibleRegionsDirty;
bool mDeferReleaseConsole;
bool mFreezeDisplay;
+ int32_t mElectronBeamAnimationMode;
int32_t mFreezeCount;
nsecs_t mFreezeDisplayTime;
Vector< sp<LayerBase> > mVisibleLayersSortedByZ;