diff options
66 files changed, 2002 insertions, 1017 deletions
diff --git a/api/11.xml b/api/11.xml index 43bb440e7e43..e2f8025547b7 100644 --- a/api/11.xml +++ b/api/11.xml @@ -61129,17 +61129,6 @@ visibility="public" > </method> -<method name="getGL" - return="javax.microedition.khronos.opengles.GL" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> <method name="getHeight" return="int" abstract="false" diff --git a/api/current.xml b/api/current.xml index 7302fd6f4d3b..f80701b0385a 100644 --- a/api/current.xml +++ b/api/current.xml @@ -1255,17 +1255,6 @@ visibility="public" > </field> -<field name="WRITE_MEDIA_STORAGE" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.permission.WRITE_MEDIA_STORAGE"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="WRITE_SECURE_SETTINGS" type="java.lang.String" transient="false" @@ -19996,6 +19985,42 @@ </parameter> </method> </class> +<class name="ArgbEvaluator" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.animation.TypeEvaluator"> +</implements> +<constructor name="ArgbEvaluator" + type="android.animation.ArgbEvaluator" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<method name="evaluate" + return="java.lang.Object" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fraction" type="float"> +</parameter> +<parameter name="startValue" type="java.lang.Object"> +</parameter> +<parameter name="endValue" type="java.lang.Object"> +</parameter> +</method> +</class> <class name="DoubleEvaluator" extends="java.lang.Object" abstract="false" @@ -20962,42 +20987,6 @@ </parameter> </method> </class> -<class name="RGBEvaluator" - extends="java.lang.Object" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<implements name="android.animation.TypeEvaluator"> -</implements> -<constructor name="RGBEvaluator" - type="android.animation.RGBEvaluator" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<method name="evaluate" - return="java.lang.Object" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="fraction" type="float"> -</parameter> -<parameter name="startValue" type="java.lang.Object"> -</parameter> -<parameter name="endValue" type="java.lang.Object"> -</parameter> -</method> -</class> <interface name="TimeInterpolator" abstract="true" static="false" @@ -58409,6 +58398,17 @@ visibility="public" > </method> +<method name="isEnabled" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <field name="applicationInfo" type="android.content.pm.ApplicationInfo" transient="false" @@ -78255,17 +78255,6 @@ visibility="public" > </method> -<method name="getGL" - return="javax.microedition.khronos.opengles.GL" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="deprecated" - visibility="protected" -> -</method> <method name="getHeight" return="int" abstract="false" @@ -140839,6 +140828,17 @@ visibility="public" > </method> +<method name="isExternalStorageEmulated" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="isExternalStorageRemovable" return="boolean" abstract="false" @@ -166366,8 +166366,6 @@ </parameter> <parameter name="mips" type="android.renderscript.Allocation.MipmapControl"> </parameter> -<parameter name="layout" type="android.renderscript.Allocation.CubemapLayout"> -</parameter> <parameter name="usage" type="int"> </parameter> </method> @@ -166385,8 +166383,6 @@ </parameter> <parameter name="b" type="android.graphics.Bitmap"> </parameter> -<parameter name="layout" type="android.renderscript.Allocation.CubemapLayout"> -</parameter> </method> <method name="createFromBitmap" return="android.renderscript.Allocation" @@ -166646,39 +166642,6 @@ > </field> </class> -<class name="Allocation.CubemapLayout" - extends="java.lang.Enum" - abstract="false" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -<method name="valueOf" - return="android.renderscript.Allocation.CubemapLayout" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="name" type="java.lang.String"> -</parameter> -</method> -<method name="values" - return="android.renderscript.Allocation.CubemapLayout[]" - abstract="false" - native="false" - synchronized="false" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</method> -</class> <class name="Allocation.MipmapControl" extends="java.lang.Enum" abstract="false" @@ -258070,7 +258033,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="arg0" type="T"> +<parameter name="t" type="T"> </parameter> </method> </interface> diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java index 6e589e435b15..bcab66eaa6f2 100644 --- a/core/java/android/animation/AnimatorInflater.java +++ b/core/java/android/animation/AnimatorInflater.java @@ -215,7 +215,7 @@ public class AnimatorInflater { (toType <= TypedValue.TYPE_LAST_COLOR_INT))) { // special case for colors: ignore valueType and get ints getFloats = false; - anim.setEvaluator(new RGBEvaluator()); + anim.setEvaluator(new ArgbEvaluator()); } if (getFloats) { diff --git a/core/java/android/animation/RGBEvaluator.java b/core/java/android/animation/ArgbEvaluator.java index bae0af0c8b36..c3875bee2c2d 100644 --- a/core/java/android/animation/RGBEvaluator.java +++ b/core/java/android/animation/ArgbEvaluator.java @@ -20,7 +20,7 @@ package android.animation; * This evaluator can be used to perform type interpolation between integer * values that represent ARGB colors. */ -public class RGBEvaluator implements TypeEvaluator { +public class ArgbEvaluator implements TypeEvaluator { /** * This function returns the calculated in-between value for a color diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index cfecec12f6ca..f8844733f9d2 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -862,7 +862,7 @@ public class ValueAnimator extends Animator { * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values * are not one of these primitive types, or if different evaluation is desired (such as is * necessary with int values that represent colors), a custom evaluator needs to be assigned. - * For example, when running an animation on color values, the {@link RGBEvaluator} + * For example, when running an animation on color values, the {@link ArgbEvaluator} * should be used to get correct RGB color interpolation. * * <p>If this ValueAnimator has only one set of values being animated between, this evaluator diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java index f16c4efdfaf4..28124775fb95 100644 --- a/core/java/android/content/pm/ComponentInfo.java +++ b/core/java/android/content/pm/ComponentInfo.java @@ -98,6 +98,13 @@ public class ComponentInfo extends PackageItemInfo { } return name; } + + /** + * Return whether this component and its enclosing application are enabled. + */ + public boolean isEnabled() { + return enabled && applicationInfo.enabled; + } /** * Return the icon resource identifier to use for this component. If diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java index 5e96928515e6..c76cc6c6e832 100644 --- a/core/java/android/database/sqlite/SQLiteStatement.java +++ b/core/java/android/database/sqlite/SQLiteStatement.java @@ -131,6 +131,10 @@ public class SQLiteStatement extends SQLiteProgram long retValue = native_1x1_long(); mDatabase.logTimeStat(mSql, timeStart); return retValue; + } catch (SQLiteDoneException e) { + throw new SQLiteDoneException( + "expected 1 row from this query but query returned no data. check the query: " + + mSql); } finally { releaseAndUnlock(); } @@ -150,6 +154,10 @@ public class SQLiteStatement extends SQLiteProgram String retValue = native_1x1_string(); mDatabase.logTimeStat(mSql, timeStart); return retValue; + } catch (SQLiteDoneException e) { + throw new SQLiteDoneException( + "expected 1 row from this query but query returned no data. check the query: " + + mSql); } finally { releaseAndUnlock(); } @@ -172,6 +180,10 @@ public class SQLiteStatement extends SQLiteProgram } catch (IOException ex) { Log.e(TAG, "simpleQueryForBlobFileDescriptor() failed", ex); return null; + } catch (SQLiteDoneException e) { + throw new SQLiteDoneException( + "expected 1 row from this query but query returned no data. check the query: " + + mSql); } finally { releaseAndUnlock(); } diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 4688847b0354..4f188f8576d4 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -414,8 +414,6 @@ public class Environment { * emulated. If true, the device does not have real external storage * and certain system services such as the package manager use this * to determine where to install an application. - * - * @hide */ public static boolean isExternalStorageEmulated() { if (mIsExternalStorageEmulated == null) { diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index d1ca0c9108fa..ee091f04b330 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -3430,12 +3430,6 @@ public final class ContactsContract { * <th colspan='4'>PhoneLookup</th> * </tr> * <tr> - * <td>long</td> - * <td>{@link #_ID}</td> - * <td>read-only</td> - * <td>Data row ID.</td> - * </tr> - * <tr> * <td>String</td> * <td>{@link #NUMBER}</td> * <td>read-only</td> @@ -3462,6 +3456,12 @@ public final class ContactsContract { * <th colspan='4'>Join with {@link Contacts}</th> * </tr> * <tr> + * <td>long</td> + * <td>{@link #_ID}</td> + * <td>read-only</td> + * <td>Contact ID.</td> + * </tr> + * <tr> * <td>String</td> * <td>{@link #LOOKUP_KEY}</td> * <td>read-only</td> diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 366393c9ff99..7c55f7b328c8 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -1073,11 +1073,6 @@ public final class ViewRoot extends Handler implements ViewParent, } } surfaceChanged = true; - - if (mAttachInfo.mHardwareRenderer != null) { - // This will bail out early if already initialized - mAttachInfo.mHardwareRenderer.initialize(mHolder); - } } if (surfaceChanged) { mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder, diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java index 4c2f0b459806..1313fccb8bde 100644 --- a/core/java/android/webkit/WebTextView.java +++ b/core/java/android/webkit/WebTextView.java @@ -204,11 +204,6 @@ import junit.framework.Assert; case KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_DOWN: - if (!mWebView.nativeCursorMatchesFocus()) { - return down ? mWebView.onKeyDown(keyCode, event) : mWebView - .onKeyUp(keyCode, event); - - } isArrowKey = true; break; } @@ -258,10 +253,6 @@ import junit.framework.Assert; if (isPopupShowing()) { return super.dispatchKeyEvent(event); } - if (!mWebView.nativeCursorMatchesFocus()) { - return down ? mWebView.onKeyDown(keyCode, event) : mWebView - .onKeyUp(keyCode, event); - } // Center key should be passed to a potential onClick if (!down) { mWebView.centerKeyPressOnTextField(); @@ -753,12 +744,7 @@ import junit.framework.Assert; if (event.getAction() != MotionEvent.ACTION_MOVE) { return false; } - // If the Cursor is not on the text input, webview should handle the - // trackball - if (!mWebView.nativeCursorMatchesFocus()) { - return mWebView.onTrackballEvent(event); - } - Spannable text = (Spannable) getText(); + Spannable text = getText(); MovementMethod move = getMovementMethod(); if (move != null && getLayout() != null && move.onTrackballEvent(this, text, event)) { diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index f98ad74de7eb..4a9e44189fa0 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -56,6 +56,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.SystemClock; import android.provider.Settings; import android.speech.tts.TextToSpeech; import android.text.Selection; @@ -2617,10 +2618,6 @@ public class WebView extends AbsoluteLayout private int computeRealHorizontalScrollRange() { if (mDrawHistory) { return mHistoryWidth; - } else if (mHorizontalScrollBarMode == SCROLLBAR_ALWAYSOFF - && !mZoomManager.canZoomOut()) { - // only honor the scrollbar mode when it is at minimum zoom level - return computeHorizontalScrollExtent(); } else { // to avoid rounding error caused unnecessary scrollbar, use floor return (int) Math.floor(mContentWidth * mZoomManager.getScale()); @@ -2651,10 +2648,6 @@ public class WebView extends AbsoluteLayout private int computeRealVerticalScrollRange() { if (mDrawHistory) { return mHistoryHeight; - } else if (mVerticalScrollBarMode == SCROLLBAR_ALWAYSOFF - && !mZoomManager.canZoomOut()) { - // only honor the scrollbar mode when it is at minimum zoom level - return computeVerticalScrollExtent(); } else { // to avoid rounding error caused unnecessary scrollbar, use floor return (int) Math.floor(mContentHeight * mZoomManager.getScale()); @@ -5329,17 +5322,10 @@ public class WebView extends AbsoluteLayout + " numPointers=" + ev.getPointerCount()); } - int action = ev.getAction(); - float x = ev.getX(); - float y = ev.getY(); - long eventTime = ev.getEventTime(); - - // mDeferMultitouch is a hack for layout tests, where it is used to - // force passing multi-touch events to webkit. - // FIXME: always pass multi-touch events to webkit and remove everything - // related to mDeferMultitouch. - if (ev.getPointerCount() > 1 && - (mDeferMultitouch || mZoomManager.isZoomScaleFixed())) { + // Always pass multi-touch event to WebKit first. + // If WebKit doesn't consume it and set preventDefault to true, + // WebView's private handler will handle it. + if (ev.getPointerCount() > 1) { if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "passing " + ev.getPointerCount() + " points to webkit"); } @@ -5347,59 +5333,15 @@ public class WebView extends AbsoluteLayout return true; } - final ScaleGestureDetector detector = - mZoomManager.getMultiTouchGestureDetector(); - - if (mZoomManager.supportsMultiTouchZoom() && ev.getPointerCount() > 1) { - if (!detector.isInProgress() && - ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) { - // Insert a fake pointer down event in order to start - // the zoom scale detector. - MotionEvent temp = MotionEvent.obtain(ev); - // Clear the original event and set it to - // ACTION_POINTER_DOWN. - try { - temp.setAction(temp.getAction() & - ~MotionEvent.ACTION_MASK | - MotionEvent.ACTION_POINTER_DOWN); - detector.onTouchEvent(temp); - } finally { - temp.recycle(); - } - } - - detector.onTouchEvent(ev); + return handleTouchEventCommon(ev); + } - if (detector.isInProgress()) { - mLastTouchTime = eventTime; - cancelLongPress(); - mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - if (!mZoomManager.supportsPanDuringZoom()) { - return true; - } - mTouchMode = TOUCH_DRAG_MODE; - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - } + private boolean handleTouchEventCommon(MotionEvent ev) { + int action = ev.getAction(); + float x = ev.getX(); + float y = ev.getY(); + long eventTime = ev.getEventTime(); - x = detector.getFocusX(); - y = detector.getFocusY(); - action = ev.getAction() & MotionEvent.ACTION_MASK; - if (action == MotionEvent.ACTION_POINTER_DOWN) { - cancelTouch(); - action = MotionEvent.ACTION_DOWN; - } else if (action == MotionEvent.ACTION_POINTER_UP) { - // set mLastTouchX/Y to the remaining point - mLastTouchX = x; - mLastTouchY = y; - } else if (action == MotionEvent.ACTION_MOVE) { - // negative x or y indicate it is on the edge, skip it. - if (x < 0 || y < 0) { - return true; - } - } - } // Due to the touch screen edge effect, a touch closer to the edge // always snapped to the edge. As getViewWidth() can be different from @@ -5612,22 +5554,6 @@ public class WebView extends AbsoluteLayout break; } - // Only lock dragging to one axis if we don't have a scale in progress. - // Scaling implies free-roaming movement. Note this is only ever a question - // if mZoomManager.supportsPanDuringZoom() is true. - if (detector != null && !detector.isInProgress()) { - // if it starts nearly horizontal or vertical, enforce it - int ax = Math.abs(deltaX); - int ay = Math.abs(deltaY); - if (ax > MAX_SLOPE_FOR_DIAG * ay) { - mSnapScrollMode = SNAP_X; - mSnapPositive = deltaX > 0; - } else if (ay > MAX_SLOPE_FOR_DIAG * ax) { - mSnapScrollMode = SNAP_Y; - mSnapPositive = deltaY > 0; - } - } - mTouchMode = TOUCH_DRAG_MODE; mLastTouchX = x; mLastTouchY = y; @@ -5884,13 +5810,82 @@ public class WebView extends AbsoluteLayout ted.mPoints[c] = new Point(x, y); } ted.mMetaState = ev.getMetaState(); - ted.mReprocess = mDeferTouchProcess; + ted.mReprocess = true; + ted.mMotionEvent = MotionEvent.obtain(ev); mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted); cancelLongPress(); mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); mPreventDefault = PREVENT_DEFAULT_IGNORE; } + private boolean handleMultiTouchInWebView(MotionEvent ev) { + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "multi-touch: " + ev + " at " + ev.getEventTime() + + " mTouchMode=" + mTouchMode + + " numPointers=" + ev.getPointerCount() + + " scrolloffset=(" + mScrollX + "," + mScrollY + ")"); + } + + final ScaleGestureDetector detector = + mZoomManager.getMultiTouchGestureDetector(); + int action = ev.getAction(); + float x = ev.getX(); + float y = ev.getY(); + long eventTime = ev.getEventTime(); + + if (!detector.isInProgress() && + ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) { + // Insert a fake pointer down event in order to start + // the zoom scale detector. + MotionEvent temp = MotionEvent.obtain(ev); + // Clear the original event and set it to + // ACTION_POINTER_DOWN. + try { + temp.setAction(temp.getAction() & + ~MotionEvent.ACTION_MASK | + MotionEvent.ACTION_POINTER_DOWN); + detector.onTouchEvent(temp); + } finally { + temp.recycle(); + } + } + + detector.onTouchEvent(ev); + + if (detector.isInProgress()) { + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "detector is in progress"); + } + mLastTouchTime = eventTime; + cancelLongPress(); + mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); + if (!mZoomManager.supportsPanDuringZoom()) { + return false; + } + mTouchMode = TOUCH_DRAG_MODE; + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + } + + action = ev.getAction() & MotionEvent.ACTION_MASK; + if (action == MotionEvent.ACTION_POINTER_DOWN) { + cancelTouch(); + action = MotionEvent.ACTION_DOWN; + } else if (action == MotionEvent.ACTION_POINTER_UP) { + // set mLastTouchX/Y to the remaining point + mLastTouchX = x; + mLastTouchY = y; + } else if (action == MotionEvent.ACTION_MOVE) { + // negative x or y indicate it is on the edge, skip it. + if (x < 0 || y < 0) { + return false; + } + } + + return handleTouchEventCommon(ev); + } + private void cancelWebCoreTouchEvent(int x, int y, boolean removeEvents) { if (shouldForwardTouchEvent()) { if (removeEvents) { @@ -7263,6 +7258,13 @@ public class WebView extends AbsoluteLayout // prevent default is not called in WebCore, so the // message needs to be reprocessed in UI TouchEventData ted = (TouchEventData) msg.obj; + + if (ted.mPoints.length > 1) { // for multi-touch. + handleMultiTouchInWebView(ted.mMotionEvent); + break; + } + + // Following is for single touch. switch (ted.mAction) { case MotionEvent.ACTION_DOWN: mLastDeferTouchX = contentToViewX(ted.mPoints[0].x) @@ -8088,7 +8090,6 @@ public class WebView extends AbsoluteLayout private native int nativeCursorFramePointer(); private native Rect nativeCursorNodeBounds(); private native int nativeCursorNodePointer(); - /* package */ native boolean nativeCursorMatchesFocus(); private native boolean nativeCursorIntersects(Rect visibleRect); private native boolean nativeCursorIsAnchor(); private native boolean nativeCursorIsTextInput(); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index a482b741a812..c874160ffaf6 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -33,6 +33,7 @@ import android.provider.MediaStore; import android.util.Log; import android.util.SparseBooleanArray; import android.view.KeyEvent; +import android.view.MotionEvent; import android.view.SurfaceView; import android.view.View; import android.webkit.DeviceMotionService; @@ -830,6 +831,7 @@ final class WebViewCore { Point[] mPoints; int mMetaState; boolean mReprocess; + MotionEvent mMotionEvent; } static class GeolocationPermissionsData { diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java index 7b9def06db8f..e1392ae14225 100644 --- a/core/java/android/webkit/WebViewDatabase.java +++ b/core/java/android/webkit/WebViewDatabase.java @@ -223,6 +223,7 @@ public class WebViewDatabase { null); } } + mDatabase.enableWriteAheadLogging(); // mDatabase should not be null, // the only case is RequestAPI test has problem to create db @@ -233,7 +234,7 @@ public class WebViewDatabase { } if (mDatabase.getVersion() != DATABASE_VERSION) { - mDatabase.beginTransaction(); + mDatabase.beginTransactionNonExclusive(); try { upgradeDatabase(); mDatabase.setTransactionSuccessful(); @@ -261,6 +262,7 @@ public class WebViewDatabase { CACHE_DATABASE_FILE, 0, null); } } + mCacheDatabase.enableWriteAheadLogging(); // mCacheDatabase should not be null, // the only case is RequestAPI test has problem to create db @@ -271,7 +273,7 @@ public class WebViewDatabase { } if (mCacheDatabase.getVersion() != CACHE_DATABASE_VERSION) { - mCacheDatabase.beginTransaction(); + mCacheDatabase.beginTransactionNonExclusive(); try { upgradeCacheDatabase(); bootstrapCacheDatabase(); @@ -648,7 +650,7 @@ public class WebViewDatabase { + "WebViewWorkerThread instead of from " + Thread.currentThread().getName()); } - mCacheDatabase.beginTransaction(); + mCacheDatabase.beginTransactionNonExclusive(); return true; } return false; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index b85670c233d6..bccde8d2cf9f 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -4810,7 +4810,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (mFiltered && mPopup != null && mPopup.isShowing()) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - getKeyDispatcherState().startTracking(event, this); + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.startTracking(event, this); + } handled = true; } else if (event.getAction() == KeyEvent.ACTION_UP && event.isTracking() && !event.isCanceled()) { diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index ee037cdc3ed8..4d8d21f4a3e0 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -607,10 +607,16 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe // special case for the back key, we do not even try to send it // to the drop down list but instead, consume it immediately if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - getKeyDispatcherState().startTracking(event, this); + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.startTracking(event, this); + } return true; } else if (event.getAction() == KeyEvent.ACTION_UP) { - getKeyDispatcherState().handleUpEvent(event); + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.handleUpEvent(event); + } if (event.isTracking() && !event.isCanceled()) { dismissDropDown(); return true; diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index 3bba816b8bff..444a163d385d 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -915,10 +915,16 @@ public class ListPopupWindow { // to the drop down list but instead, consume it immediately final View anchorView = mDropDownAnchorView; if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - anchorView.getKeyDispatcherState().startTracking(event, this); + KeyEvent.DispatcherState state = anchorView.getKeyDispatcherState(); + if (state != null) { + state.startTracking(event, this); + } return true; } else if (event.getAction() == KeyEvent.ACTION_UP) { - anchorView.getKeyDispatcherState().handleUpEvent(event); + KeyEvent.DispatcherState state = anchorView.getKeyDispatcherState(); + if (state != null) { + state.handleUpEvent(event); + } if (event.isTracking() && !event.isCanceled()) { dismiss(); return true; diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 5a5b6f49f532..79d6a81d2461 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1468,12 +1468,17 @@ public class PopupWindow { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - getKeyDispatcherState().startTracking(event, this); - return true; - } else if (event.getAction() == KeyEvent.ACTION_UP - && getKeyDispatcherState().isTracking(event) && !event.isCanceled()) { - dismiss(); + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.startTracking(event, this); + } return true; + } else if (event.getAction() == KeyEvent.ACTION_UP) { + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null && state.isTracking(event) && !event.isCanceled()) { + dismiss(); + return true; + } } return super.dispatchKeyEvent(event); } else { diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java index 9381675524c0..463902fe53e9 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuView.java +++ b/core/java/com/android/internal/view/menu/ActionMenuView.java @@ -139,6 +139,10 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo mReserveOverflow = reserveOverflow; } + public View getOverflowButton() { + return mOverflowButton; + } + @Override protected LayoutParams generateDefaultLayoutParams() { LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index fe41f5201267..b93fac44f9fc 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -68,6 +68,10 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On } } + public void setAnchorView(View anchor) { + mAnchorView = new WeakReference<View>(anchor); + } + public void show() { if (!tryShow()) { throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 1d434421906e..67adc28286f4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -540,7 +540,8 @@ android:description="@string/permdesc_sdcardWrite" android:protectionLevel="dangerous" /> - <!-- Allows an application to write to internal media storage --> + <!-- Allows an application to write to internal media storage + @hide --> <permission android:name="android.permission.WRITE_MEDIA_STORAGE" android:permissionGroup="android.permission-group.STORAGE" android:label="@string/permlab_mediaStorageWrite" diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 66c6d8191324..184620b34cc0 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -85,8 +85,12 @@ public class Canvas { @Override protected void finalize() throws Throwable { - if (mNativeCanvas != 0) { - finalizer(mNativeCanvas); + try { + if (mNativeCanvas != 0) { + finalizer(mNativeCanvas); + } + } finally { + super.finalize(); } } } @@ -137,6 +141,8 @@ public class Canvas { * Returns null. * * @deprecated This method is not supported and should not be invoked. + * + * @hide */ @Deprecated protected GL getGL() { diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java index 53962e14cbfc..7a47c3bc88de 100644 --- a/graphics/java/android/renderscript/Allocation.java +++ b/graphics/java/android/renderscript/Allocation.java @@ -53,19 +53,6 @@ public class Allocation extends BaseObj { public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008; - public enum CubemapLayout { - VERTICAL_FACE_LIST (0), - HORIZONTAL_FACE_LIST (1), - VERTICAL_CROSS (2), - HORIZONTAL_CROSS (3); - - int mID; - CubemapLayout(int id) { - mID = id; - } - } - - public enum MipmapControl { MIPMAP_NONE(0), MIPMAP_FULL(1), @@ -416,33 +403,41 @@ public class Allocation extends BaseObj { USAGE_GRAPHICS_TEXTURE); } + /** + * Creates a cubemap allocation from a bitmap containing the + * horizontal list of cube faces. Each individual face must be + * the same size and power of 2 + * + * @param rs + * @param b bitmap with cubemap faces layed out in the following + * format: right, left, top, bottom, front, back + * @param mips specifies desired mipmap behaviour for the cubemap + * @param usage bitfield specifying how the cubemap is utilized + * + **/ static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b, MipmapControl mips, - CubemapLayout layout, int usage) { rs.validate(); int height = b.getHeight(); int width = b.getWidth(); - if (layout != CubemapLayout.VERTICAL_FACE_LIST) { - throw new RSIllegalArgumentException("Only vertical face list supported"); - } - if (height % 6 != 0) { + if (width % 6 != 0) { throw new RSIllegalArgumentException("Cubemap height must be multiple of 6"); } - if (height / 6 != width) { + if (width / 6 != height) { throw new RSIllegalArgumentException("Only square cobe map faces supported"); } - boolean isPow2 = (width & (width - 1)) == 0; + boolean isPow2 = (height & (height - 1)) == 0; if (!isPow2) { throw new RSIllegalArgumentException("Only power of 2 cube faces supported"); } Element e = elementFromBitmap(rs, b); Type.Builder tb = new Type.Builder(rs, e); - tb.setX(width); - tb.setY(width); + tb.setX(height); + tb.setY(height); tb.setFaces(true); tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL); Type t = tb.create(); @@ -454,10 +449,9 @@ public class Allocation extends BaseObj { return new Allocation(id, rs, t, usage); } - static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b, - CubemapLayout layout) { + static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b) { return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE, - layout, USAGE_GRAPHICS_TEXTURE); + USAGE_GRAPHICS_TEXTURE); } static public Allocation createFromBitmapResource(RenderScript rs, diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 40dd11770f3a..406d09f4d9de 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -53,6 +53,10 @@ Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO), mDebugLevel = readDebugLevel(); LOGD("Enabling debug mode %d", mDebugLevel); + +#if RENDER_LAYERS_AS_REGIONS + LOGD("Layers will be composited as regions"); +#endif } Caches::~Caches() { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 9613c5f6b8ff..99bb6f01031a 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -162,6 +162,11 @@ void OpenGLRenderer::finish() { GLenum status = GL_NO_ERROR; while ((status = glGetError()) != GL_NO_ERROR) { LOGD("GL error from OpenGLRenderer: 0x%x", status); + switch (status) { + case GL_OUT_OF_MEMORY: + LOGE(" OpenGLRenderer is out of memory!"); + break; + } } #endif #if DEBUG_MEMORY_USAGE @@ -599,43 +604,23 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { size_t count; const android::Rect* rects = layer->region.getArray(&count); - setupDraw(); - - ProgramDescription description; - description.hasTexture = true; - const float alpha = layer->alpha / 255.0f; - const bool setColor = description.setColor(alpha, alpha, alpha, alpha); - chooseBlending(layer->blend || layer->alpha < 255, layer->mode, description, false); - - useProgram(mCaches.programCache.get(description)); - - // Texture - bindTexture(layer->texture); - glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); - - // Always premultiplied - if (setColor) { - mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha); - } - - // Mesh - int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); - glEnableVertexAttribArray(texCoordsSlot); - - mModelView.loadIdentity(); - mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); - const float texX = 1.0f / float(layer->width); const float texY = 1.0f / float(layer->height); TextureVertex* mesh = mCaches.getRegionMesh(); GLsizei numQuads = 0; - glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, - gMeshStride, &mesh[0].position[0]); - glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, - gMeshStride, &mesh[0].texture[0]); + setupDraw(); + setupDrawWithTexture(); + setupDrawColor(alpha, alpha, alpha, alpha); + setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false); + setupDrawProgram(); + setupDrawDirtyRegionsDisabled(); + setupDrawPureColorUniforms(); + setupDrawTexture(layer->texture); + setupDrawModelViewIdentity(); + setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0]); for (size_t i = 0; i < count; i++) { const android::Rect* r = &rects[i]; @@ -665,7 +650,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDisableVertexAttribArray(texCoordsSlot); + finishDrawTexture(); #if DEBUG_LAYERS_AS_REGIONS uint32_t colors[] = { @@ -1181,7 +1166,6 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int } void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { - // TODO: Should do quickReject for each line if (mSnapshot->isIgnored()) return; const bool isAA = paint->isAntiAlias(); @@ -1195,6 +1179,7 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { getAlphaAndMode(paint, &alpha, &mode); int verticesCount = count >> 2; + int generatedVerticesCount = 0; if (!isHairLine) { // TODO: AA needs more vertices verticesCount *= 6; @@ -1241,31 +1226,55 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { vec2 p3 = b + n; vec2 p4 = b - n; - // Draw the line as 2 triangles, could be optimized - // by using only 4 vertices and the correct indices - // Also we should probably used non textured vertices - // when line AA is disabled to save on bandwidth - TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p2.x, p2.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p4.x, p4.y, 0.0f, 0.0f); - - // TODO: Mark the dirty regions when RENDER_LAYERS_AS_REGIONS is set + const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x))); + const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x))); + const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y))); + const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y))); + + if (!quickReject(left, top, right, bottom)) { + // Draw the line as 2 triangles, could be optimized + // by using only 4 vertices and the correct indices + // Also we should probably used non textured vertices + // when line AA is disabled to save on bandwidth + TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); + TextureVertex::set(vertex++, p2.x, p2.y, 0.0f, 0.0f); + TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); + TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); + TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); + TextureVertex::set(vertex++, p4.x, p4.y, 0.0f, 0.0f); + + generatedVerticesCount += 6; + + dirtyLayer(left, top, right, bottom, *mSnapshot->transform); + } } - // GL_LINE does not give the result we want to match Skia - glDrawArrays(GL_TRIANGLES, 0, verticesCount); + if (generatedVerticesCount > 0) { + // GL_LINE does not give the result we want to match Skia + glDrawArrays(GL_TRIANGLES, 0, generatedVerticesCount); + } } else { // TODO: Handle the AA case for (int i = 0; i < count; i += 4) { - TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); - TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f); + const float left = fmin(points[i], points[i + 1]); + const float right = fmax(points[i], points[i + 1]); + const float top = fmin(points[i + 2], points[i + 3]); + const float bottom = fmax(points[i + 2], points[i + 3]); + + if (!quickReject(left, top, right, bottom)) { + TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); + TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f); + + generatedVerticesCount += 2; + + dirtyLayer(left, top, right, bottom, *mSnapshot->transform); + } } - glLineWidth(1.0f); - glDrawArrays(GL_LINES, 0, verticesCount); + if (generatedVerticesCount > 0) { + glLineWidth(1.0f); + glDrawArrays(GL_LINES, 0, generatedVerticesCount); + } } } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index c4749363711e..6a0d7ea18dfb 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -26,7 +26,7 @@ */ // If turned on, layers drawn inside FBOs are optimized with regions -#define RENDER_LAYERS_AS_REGIONS 0 +#define RENDER_LAYERS_AS_REGIONS 1 /** * Debug level for app developers. diff --git a/libs/rs/java/Samples/res/drawable/cubemap_test.png b/libs/rs/java/Samples/res/drawable/cubemap_test.png Binary files differindex 75ad0a421775..baf35d0acbe9 100644 --- a/libs/rs/java/Samples/res/drawable/cubemap_test.png +++ b/libs/rs/java/Samples/res/drawable/cubemap_test.png diff --git a/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java b/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java index 5430a1307b85..1afcee335a50 100644 --- a/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java +++ b/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java @@ -22,7 +22,6 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.renderscript.*; -import android.renderscript.Allocation.CubemapLayout; import android.renderscript.Allocation.MipmapControl; import android.renderscript.Program.TextureType; import android.renderscript.ProgramStore.DepthFunc; @@ -318,8 +317,7 @@ public class RsBenchRS { mTexTransparent = loadTextureARGB(R.drawable.leaf); mTexChecker = loadTextureRGB(R.drawable.checker); Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test); - mTexCube = Allocation.createCubemapFromBitmap(mRS, b, - Allocation.CubemapLayout.VERTICAL_FACE_LIST); + mTexCube = Allocation.createCubemapFromBitmap(mRS, b); mScript.set_gTexTorus(mTexTorus); mScript.set_gTexOpaque(mTexOpaque); diff --git a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java index cac105a1a703..87840a765d03 100644 --- a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java +++ b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java @@ -22,7 +22,6 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.renderscript.*; -import android.renderscript.Allocation.CubemapLayout; import android.renderscript.Font.Style; import android.renderscript.Program.TextureType; import android.renderscript.ProgramStore.DepthFunc; @@ -308,8 +307,7 @@ public class RsRenderStatesRS { mTexTransparent = loadTextureARGB(R.drawable.leaf); mTexChecker = loadTextureRGB(R.drawable.checker); Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test); - mTexCube = Allocation.createCubemapFromBitmap(mRS, b, - Allocation.CubemapLayout.VERTICAL_FACE_LIST); + mTexCube = Allocation.createCubemapFromBitmap(mRS, b); mScript.set_gTexTorus(mTexTorus); mScript.set_gTexOpaque(mTexOpaque); diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index 3608e43927c9..673ade251fff 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -831,16 +831,21 @@ RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype, return NULL; } + uint32_t faceSize = t->getDimX(); + uint32_t strideBytes = faceSize * 6 * t->getElementSizeBytes(); + uint32_t copySize = faceSize * t->getElementSizeBytes(); + uint8_t *sourcePtr = (uint8_t*)data; for (uint32_t face = 0; face < 6; face ++) { Adapter2D faceAdapter(rsc, texAlloc); faceAdapter.setFace(face); - size_t cpySize = t->getDimX() * t->getDimX() * t->getElementSizeBytes(); - memcpy(faceAdapter.getElement(0, 0), sourcePtr, cpySize); + for (uint32_t dI = 0; dI < faceSize; dI ++) { + memcpy(faceAdapter.getElement(0, dI), sourcePtr + strideBytes * dI, copySize); + } // Move the data pointer to the next cube face - sourcePtr += cpySize; + sourcePtr += copySize; if (mips == RS_ALLOCATION_MIPMAP_FULL) { Adapter2D adapt(rsc, texAlloc); diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index 96778380a5e3..31b6ec946124 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -347,7 +347,8 @@ void CameraSourceTimeLapse::stopCameraRecording() { } void CameraSourceTimeLapse::releaseRecordingFrame(const sp<IMemory>& frame) { - if (!mUseStillCameraForTimeLapse) { + if (!mUseStillCameraForTimeLapse && + mCamera != NULL) { mCamera->releaseRecordingFrame(frame); } } diff --git a/opengl/tests/hwc/hwcCommit.cpp b/opengl/tests/hwc/hwcCommit.cpp index ed74cbe7284c..66ccdae709d9 100644 --- a/opengl/tests/hwc/hwcCommit.cpp +++ b/opengl/tests/hwc/hwcCommit.cpp @@ -76,6 +76,7 @@ #include <cmath> #include <cstdlib> #include <ctime> +#include <iomanip> #include <istream> #include <libgen.h> #include <list> @@ -125,6 +126,7 @@ const struct hwc_rect defaultSourceCrop = {0, 0, 1, 1}; const struct hwc_rect defaultDisplayFrame = {0, 0, 100, 100}; // Global Constants +const uint32_t printFieldWidth = 2; const struct searchLimits { uint32_t numOverlays; HwcTestDim sourceCrop; @@ -233,6 +235,8 @@ static hwc_composer_device_t *hwcDevice; static EGLDisplay dpy; static EGLSurface surface; static EGLint width, height; +static size_t maxHeadingLen; +static vector<string> formats; // Measurements struct meas { @@ -264,6 +268,9 @@ struct meas { HwcTestDim vScaleBestDf; HwcTestDim vScaleBestSc; } sc; + vector<uint32_t> overlapBlendNone; + vector<uint32_t> overlapBlendPremult; + vector<uint32_t> overlapBlendCoverage; }; vector<meas> measurements; @@ -292,9 +299,14 @@ Rational scVScale(uint32_t format, const HwcTestDim& dfMin, const HwcTestDim& dfMax, const HwcTestDim& scMin, const HwcTestDim& scMax, HwcTestDim& outBestDf, HwcTestDim& outBestSc); +uint32_t numOverlapping(uint32_t backgroundFormat, uint32_t foregroundFormat, + uint32_t backgroundBlend, uint32_t foregroundBlend); string transformList2str(const list<uint32_t>& transformList); string blendList2str(const list<uint32_t>& blendList); void init(void); +void printFormatHeadings(size_t indent); +void printOverlapLine(size_t indent, const string formatStr, + const vector<uint32_t>& results); void printSyntax(const char *cmd); // Command-line option settings @@ -332,7 +344,6 @@ main(int argc, char *argv[]) bool error; string str; char cmd[MAXCMD]; - list<string> formats; list<Rectangle> rectList; testSetLogCatTag(LOG_TAG); @@ -395,6 +406,13 @@ main(int argc, char *argv[]) } } + // Determine length of longest specified graphic format. + // This value is used for output formating + for (vector<string>::iterator it = formats.begin(); + it != formats.end(); ++it) { + maxHeadingLen = max(maxHeadingLen, it->length()); + } + // Stop framework rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK); if (rv >= (signed) sizeof(cmd) - 1) { @@ -411,7 +429,7 @@ main(int argc, char *argv[]) init(); // For each of the graphic formats - for (list<string>::iterator itFormat = formats.begin(); + for (vector<string>::iterator itFormat = formats.begin(); itFormat != formats.end(); ++itFormat) { // Locate hwcTestLib structure that describes this format @@ -539,7 +557,65 @@ main(int argc, char *argv[]) testPrintI(" VScale Best Source Crop: %s", ((string) measPtr->sc.vScaleBestSc).c_str()); + // Overlap two graphic formats and different blends + // Results displayed after all overlap measurments with + // current format in the foreground + // TODO: make measurments with background blend other than + // none. All of these measurements are done with a + // background blend of HWC_BLENDING_NONE, with the + // blend type of the foregound being varied. + uint32_t foregroundFormat = format->format; + for (vector<string>::iterator it = formats.begin(); + it != formats.end(); ++it) { + uint32_t num; + + const struct hwcTestGraphicFormat *backgroundFormatPtr + = hwcTestGraphicFormatLookup((*it).c_str()); + uint32_t backgroundFormat = backgroundFormatPtr->format; + + num = numOverlapping(backgroundFormat, foregroundFormat, + HWC_BLENDING_NONE, HWC_BLENDING_NONE); + measPtr->overlapBlendNone.push_back(num); + + num = numOverlapping(backgroundFormat, foregroundFormat, + HWC_BLENDING_NONE, HWC_BLENDING_PREMULT); + measPtr->overlapBlendPremult.push_back(num); + + num = numOverlapping(backgroundFormat, foregroundFormat, + HWC_BLENDING_NONE, HWC_BLENDING_COVERAGE); + measPtr->overlapBlendCoverage.push_back(num); + } + + } + + // Display overlap results + size_t indent = 2; + testPrintI("overlapping blend: none"); + printFormatHeadings(indent); + for (vector<string>::iterator it = formats.begin(); + it != formats.end(); ++it) { + printOverlapLine(indent, *it, measurements[it + - formats.begin()].overlapBlendNone); + } + testPrintI(""); + + testPrintI("overlapping blend: premult"); + printFormatHeadings(indent); + for (vector<string>::iterator it = formats.begin(); + it != formats.end(); ++it) { + printOverlapLine(indent, *it, measurements[it + - formats.begin()].overlapBlendPremult); + } + testPrintI(""); + + testPrintI("overlapping blend: coverage"); + printFormatHeadings(indent); + for (vector<string>::iterator it = formats.begin(); + it != formats.end(); ++it) { + printOverlapLine(indent, *it, measurements[it + - formats.begin()].overlapBlendCoverage); } + testPrintI(""); // Start framework rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK); @@ -1204,6 +1280,33 @@ Rational scVScale(uint32_t format, return best; } +uint32_t numOverlapping(uint32_t backgroundFormat, uint32_t foregroundFormat, + uint32_t backgroundBlend, uint32_t foregroundBlend) +{ + list<Rectangle> rectList; + + Rectangle background(backgroundFormat, startDim, startDim); + background.blend = backgroundBlend; + rectList.push_back(background); + + // TODO: Handle cases where startDim is so small that adding 5 + // causes frames not to overlap. + // TODO: Handle cases where startDim is so large that adding 5 + // cause a portion or all of the foreground displayFrame + // to be off the display. + Rectangle foreground(foregroundFormat, startDim, startDim); + foreground.displayFrame.left += 5; + foreground.displayFrame.top += 5; + foreground.displayFrame.right += 5; + foreground.displayFrame.bottom += 5; + background.blend = foregroundBlend; + rectList.push_back(foreground); + + uint32_t num = numOverlays(rectList); + + return num; +} + Rectangle::Rectangle(uint32_t graphicFormat, HwcTestDim dfDim, HwcTestDim sDim) : format(graphicFormat), transform(defaultTransform), @@ -1405,6 +1508,45 @@ void init(void) hwcTestOpenHwc(&hwcDevice); } +void printFormatHeadings(size_t indent) +{ + for (size_t row = 0; row <= maxHeadingLen; row++) { + ostringstream line; + for(vector<string>::iterator it = formats.begin(); + it != formats.end(); ++it) { + if ((maxHeadingLen - row) <= it->length()) { + if (row != maxHeadingLen) { + char ch = (*it)[it->length() - (maxHeadingLen - row)]; + line << ' ' << setw(printFieldWidth) << ch; + } else { + line << ' ' << string(printFieldWidth, '-'); + } + } else { + line << ' ' << setw(printFieldWidth) << ""; + } + } + testPrintI("%*s%s", indent + maxHeadingLen, "", + line.str().c_str()); + } +} + +void printOverlapLine(size_t indent, const string formatStr, + const vector<uint32_t>& results) +{ + ostringstream line; + + line << setw(indent + maxHeadingLen - formatStr.length()) << ""; + + line << formatStr; + + for (vector<uint32_t>::const_iterator it = results.begin(); + it != results.end(); ++it) { + line << ' ' << setw(printFieldWidth) << *it; + } + + testPrintI("%s", line.str().c_str()); +} + void printSyntax(const char *cmd) { testPrintE(" %s [options] [graphicFormat] ...", diff --git a/opengl/tests/hwc/hwcTestLib.cpp b/opengl/tests/hwc/hwcTestLib.cpp index a468a9219a06..925405e69a26 100644 --- a/opengl/tests/hwc/hwcTestLib.cpp +++ b/opengl/tests/hwc/hwcTestLib.cpp @@ -475,14 +475,14 @@ void hwcTestDisplayList(hwc_layer_list_t *list) testPrintI(" displayFrame: %s", hwcTestRect2str(list->hwLayers[layer].displayFrame).c_str()); testPrintI(" scaleFactor: [%f, %f]", - (float) (list->hwLayers[layer].displayFrame.right - - list->hwLayers[layer].displayFrame.left) - / (float) (list->hwLayers[layer].sourceCrop.right - - list->hwLayers[layer].sourceCrop.left), - (float) (list->hwLayers[layer].displayFrame.bottom - - list->hwLayers[layer].displayFrame.top) - / (float) (list->hwLayers[layer].sourceCrop.bottom - - list->hwLayers[layer].sourceCrop.top)); + (float) (list->hwLayers[layer].sourceCrop.right + - list->hwLayers[layer].sourceCrop.left) + / (float) (list->hwLayers[layer].displayFrame.right + - list->hwLayers[layer].displayFrame.left), + (float) (list->hwLayers[layer].sourceCrop.bottom + - list->hwLayers[layer].sourceCrop.top) + / (float) (list->hwLayers[layer].displayFrame.bottom + - list->hwLayers[layer].displayFrame.top)); } } @@ -494,7 +494,11 @@ void hwcTestDisplayList(hwc_layer_list_t *list) */ void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list) { + uint32_t numOverlays = 0; for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { + if (list->hwLayers[layer].compositionType == HWC_OVERLAY) { + numOverlays++; + } testPrintI(" layer %u compositionType: %#x%s%s", layer, list->hwLayers[layer].compositionType, (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER) @@ -508,6 +512,7 @@ void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list) (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB) ? " CLEAR_FB" : ""); } + testPrintI(" numOverlays: %u", numOverlays); } /* diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java index 612427b21747..53c30fe73426 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java @@ -252,7 +252,11 @@ public class RecentAppsPanel extends LinearLayout implements StatusBarPanel, OnC private void refreshApplicationList() { mActivityDescriptions = getRecentTasks(); - updateUiElements(getResources().getConfiguration(), true); + if (mActivityDescriptions.size() > 0) { + updateUiElements(getResources().getConfiguration(), true); + } else { + mBar.animateCollapse(); + } } private Bitmap compositeBitmap(Bitmap background, Bitmap thumbnail) { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 2fcd04ed7e2b..38eed506d193 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -26,9 +26,11 @@ import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; import com.android.internal.view.BaseSurfaceHolder; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.StandaloneActionMode; +import com.android.internal.view.menu.ActionMenuView; import com.android.internal.view.menu.ContextMenuBuilder; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuDialogHelper; +import com.android.internal.view.menu.MenuItemImpl; import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.view.menu.MenuView; import com.android.internal.view.menu.SubMenuBuilder; @@ -881,12 +883,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // The window manager will give us a valid window token new MenuDialogHelper(subMenu).show(null); } else if (hasFeature(FEATURE_ACTION_BAR)) { - mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu); - mActionButtonPopup.show(); - Callback cb = getCallback(); - if (cb != null) { - cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu); - } + mDecor.post(new Runnable() { + public void run() { + mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu); + mActionButtonPopup.show(); + Callback cb = getCallback(); + if (cb != null) { + cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu); + } + } + }); } return true; @@ -3009,6 +3015,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) { super(context, subMenu); mSubMenu = subMenu; + + MenuBuilder parentMenu = subMenu.getRootMenu(); + MenuItemImpl item = (MenuItemImpl) subMenu.getItem(); + if (!item.isActionButton()) { + // Give a reasonable anchor to nested submenus. + ActionMenuView amv = (ActionMenuView) parentMenu.getMenuView( + MenuBuilder.TYPE_ACTION_BUTTON, null); + + View anchor = amv.getOverflowButton(); + if (anchor == null) { + anchor = amv; + } + setAnchorView(anchor); + } } @Override diff --git a/services/input/Android.mk b/services/input/Android.mk index 37804ff66d31..d7b61fc9592e 100644 --- a/services/input/Android.mk +++ b/services/input/Android.mk @@ -21,6 +21,7 @@ LOCAL_SRC_FILES:= \ InputDispatcher.cpp \ InputManager.cpp \ InputReader.cpp \ + InputWindow.cpp \ PointerController.cpp LOCAL_SHARED_LIBRARIES := \ diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h new file mode 100644 index 000000000000..cc8006217c11 --- /dev/null +++ b/services/input/InputApplication.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef _UI_INPUT_APPLICATION_H +#define _UI_INPUT_APPLICATION_H + +#include <ui/Input.h> + +#include <utils/RefBase.h> +#include <utils/Timers.h> +#include <utils/String8.h> + +namespace android { + +/* + * A handle to an application that can receive input. + * Used by the native input dispatcher to indirectly refer to the window manager objects + * that describe an application. + */ +class InputApplicationHandle : public RefBase { +protected: + InputApplicationHandle() { } + virtual ~InputApplicationHandle() { } +}; + + +/* + * An input application describes properties of an application that can receive input. + */ +struct InputApplication { + sp<InputApplicationHandle> inputApplicationHandle; + String8 name; + nsecs_t dispatchingTimeout; +}; + +} // namespace android + +#endif // _UI_INPUT_APPLICATION_H diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 89a7751a35fd..b5a4bd2da0c7 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -72,6 +72,10 @@ const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec // when an application takes too long to respond and the user has pressed an app switch key. const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec +// Amount of time to allow for an event to be dispatched (measured since its eventTime) +// before considering it stale and dropping it. +const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec + static inline nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); @@ -151,34 +155,12 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount, } -// --- InputWindow --- - -bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const { - return x >= touchableAreaLeft && x <= touchableAreaRight - && y >= touchableAreaTop && y <= touchableAreaBottom; -} - -bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x <= frameRight - && y >= frameTop && y <= frameBottom; -} - -bool InputWindow::isTrustedOverlay() const { - return layoutParamsType == TYPE_INPUT_METHOD - || layoutParamsType == TYPE_INPUT_METHOD_DIALOG - || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; -} - -bool InputWindow::supportsSplitTouch() const { - return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH; -} - - // --- InputDispatcher --- InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : mPolicy(policy), - mPendingEvent(NULL), mAppSwitchDueTime(LONG_LONG_MAX), + mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), + mNextUnblockedEvent(NULL), mDispatchEnabled(true), mDispatchFrozen(false), mFocusedWindow(NULL), mFocusedApplication(NULL), @@ -368,6 +350,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, } // Now we have an event to dispatch. + // All events are eventually dequeued and processed this way, even if we intend to drop them. assert(mPendingEvent != NULL); bool done = false; DropReason dropReason = DROP_REASON_NOT_DROPPED; @@ -376,6 +359,11 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, } else if (!mDispatchEnabled) { dropReason = DROP_REASON_DISABLED; } + + if (mNextUnblockedEvent == mPendingEvent) { + mNextUnblockedEvent = NULL; + } + switch (mPendingEvent->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = @@ -395,6 +383,13 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, dropReason = DROP_REASON_APP_SWITCH; } } + if (dropReason == DROP_REASON_NOT_DROPPED + && isStaleEventLocked(currentTime, typedEntry)) { + dropReason = DROP_REASON_STALE; + } + if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { + dropReason = DROP_REASON_BLOCKED; + } done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, &dropReason, nextWakeupTime); break; @@ -405,6 +400,13 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { dropReason = DROP_REASON_APP_SWITCH; } + if (dropReason == DROP_REASON_NOT_DROPPED + && isStaleEventLocked(currentTime, typedEntry)) { + dropReason = DROP_REASON_STALE; + } + if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { + dropReason = DROP_REASON_BLOCKED; + } done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; @@ -431,6 +433,9 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { switch (entry->type) { case EventEntry::TYPE_KEY: { + // Optimize app switch latency. + // If the application takes too long to catch up then we drop all events preceding + // the app switch key. KeyEntry* keyEntry = static_cast<KeyEntry*>(entry); if (isAppSwitchKeyEventLocked(keyEntry)) { if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { @@ -448,11 +453,63 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { } break; } + + case EventEntry::TYPE_MOTION: { + // Optimize case where the current application is unresponsive and the user + // decides to touch a window in a different application. + // If the application takes too long to catch up then we drop all events preceding + // the touch into the other window. + MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); + if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN + && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) + && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY + && mInputTargetWaitApplication != NULL) { + int32_t x = int32_t(motionEntry->firstSample.pointerCoords[0].x); + int32_t y = int32_t(motionEntry->firstSample.pointerCoords[0].y); + const InputWindow* touchedWindow = findTouchedWindowAtLocked(x, y); + if (touchedWindow + && touchedWindow->inputWindowHandle != NULL + && touchedWindow->inputWindowHandle->getInputApplicationHandle() + != mInputTargetWaitApplication) { + // User touched a different application than the one we are waiting on. + // Flag the event, and start pruning the input queue. + mNextUnblockedEvent = motionEntry; + needWake = true; + } + } + break; + } } return needWake; } +const InputWindow* InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) { + // Traverse windows from front to back to find touched window. + size_t numWindows = mWindows.size(); + for (size_t i = 0; i < numWindows; i++) { + const InputWindow* window = & mWindows.editItemAt(i); + int32_t flags = window->layoutParamsFlags; + + if (window->visible) { + if (!(flags & InputWindow::FLAG_NOT_TOUCHABLE)) { + bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE + | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0; + if (isTouchModal || window->touchableAreaContainsPoint(x, y)) { + // Found window. + return window; + } + } + } + + if (flags & InputWindow::FLAG_SYSTEM_ERROR) { + // Error window is on top but not visible, so touch is dropped. + return NULL; + } + } + return NULL; +} + void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { const char* reason; switch (dropReason) { @@ -470,6 +527,16 @@ void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropR LOGI("Dropped event because of pending overdue app switch."); reason = "inbound event was dropped because of pending overdue app switch"; break; + case DROP_REASON_BLOCKED: + LOGI("Dropped event because the current application is not responding and the user " + "has started interating with a different application."); + reason = "inbound event was dropped because the current application is not responding " + "and the user has started interating with a different application"; + break; + case DROP_REASON_STALE: + LOGI("Dropped event because it is stale."); + reason = "inbound event was dropped because it is stale"; + break; default: assert(false); return; @@ -521,6 +588,10 @@ void InputDispatcher::resetPendingAppSwitchLocked(bool handled) { #endif } +bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) { + return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT; +} + bool InputDispatcher::runCommandsLockedInterruptible() { if (mCommandQueue.isEmpty()) { return false; @@ -670,7 +741,7 @@ bool InputDispatcher::dispatchKeyLocked( CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); if (mFocusedWindow) { - commandEntry->inputChannel = mFocusedWindow->inputChannel; + commandEntry->inputWindowHandle = mFocusedWindow->inputWindowHandle; } commandEntry->keyEntry = entry; entry->refCount += 1; @@ -848,6 +919,7 @@ void InputDispatcher::resetTargetsLocked() { mCurrentInputTargetsValid = false; mCurrentInputTargets.clear(); mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; + mInputTargetWaitApplication.clear(); } void InputDispatcher::commitTargetsLocked() { @@ -866,6 +938,7 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = LONG_LONG_MAX; mInputTargetWaitTimeoutExpired = false; + mInputTargetWaitApplication.clear(); } } else { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { @@ -880,6 +953,15 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = currentTime + timeout; mInputTargetWaitTimeoutExpired = false; + mInputTargetWaitApplication.clear(); + + if (window && window->inputWindowHandle != NULL) { + mInputTargetWaitApplication = + window->inputWindowHandle->getInputApplicationHandle(); + } + if (mInputTargetWaitApplication == NULL && application) { + mInputTargetWaitApplication = application->inputApplicationHandle; + } } } @@ -2624,7 +2706,7 @@ void InputDispatcher::setFocusedApplication(const InputApplication* inputApplica void InputDispatcher::releaseFocusedApplicationLocked() { if (mFocusedApplication) { mFocusedApplication = NULL; - mFocusedApplicationStorage.handle.clear(); + mFocusedApplicationStorage.inputApplicationHandle.clear(); } } @@ -2860,7 +2942,8 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { } } -status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) { +status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { #if DEBUG_REGISTRATION LOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(), toString(monitor)); @@ -2875,7 +2958,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan return BAD_VALUE; } - sp<Connection> connection = new Connection(inputChannel); + sp<Connection> connection = new Connection(inputChannel, inputWindowHandle); status_t status = connection->initialize(); if (status) { LOGE("Failed to initialize input publisher for input channel '%s', status=%d", @@ -3002,9 +3085,10 @@ void InputDispatcher::onANRLocked( CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doNotifyANRLockedInterruptible); if (application) { - commandEntry->inputApplicationHandle = application->handle; + commandEntry->inputApplicationHandle = application->inputApplicationHandle; } if (window) { + commandEntry->inputWindowHandle = window->inputWindowHandle; commandEntry->inputChannel = window->inputChannel; } } @@ -3025,7 +3109,7 @@ void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( if (connection->status != Connection::STATUS_ZOMBIE) { mLock.unlock(); - mPolicy->notifyInputChannelBroken(connection->inputChannel); + mPolicy->notifyInputChannelBroken(connection->inputWindowHandle); mLock.lock(); } @@ -3036,7 +3120,7 @@ void InputDispatcher::doNotifyANRLockedInterruptible( mLock.unlock(); nsecs_t newTimeout = mPolicy->notifyANR( - commandEntry->inputApplicationHandle, commandEntry->inputChannel); + commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle); mLock.lock(); @@ -3052,7 +3136,7 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( mLock.unlock(); - bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputChannel, + bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, &event, entry->policyFlags); mLock.lock(); @@ -3095,7 +3179,7 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( mLock.unlock(); - bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel, + bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, &event, keyEntry->policyFlags, &event); mLock.lock(); @@ -3604,8 +3688,10 @@ bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& mement // --- InputDispatcher::Connection --- -InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) : - status(STATUS_NORMAL), inputChannel(inputChannel), inputPublisher(inputChannel), +InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle) : + status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle), + inputPublisher(inputChannel), lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) { } diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index c8beab2aabae..11e511732061 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -33,6 +33,9 @@ #include <unistd.h> #include <limits.h> +#include "InputWindow.h" +#include "InputApplication.h" + namespace android { @@ -116,137 +119,6 @@ struct InputTarget { /* - * An input window describes the bounds of a window that can receive input. - */ -struct InputWindow { - // Window flags from WindowManager.LayoutParams - enum { - FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, - FLAG_DIM_BEHIND = 0x00000002, - FLAG_BLUR_BEHIND = 0x00000004, - FLAG_NOT_FOCUSABLE = 0x00000008, - FLAG_NOT_TOUCHABLE = 0x00000010, - FLAG_NOT_TOUCH_MODAL = 0x00000020, - FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, - FLAG_KEEP_SCREEN_ON = 0x00000080, - FLAG_LAYOUT_IN_SCREEN = 0x00000100, - FLAG_LAYOUT_NO_LIMITS = 0x00000200, - FLAG_FULLSCREEN = 0x00000400, - FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, - FLAG_DITHER = 0x00001000, - FLAG_SECURE = 0x00002000, - FLAG_SCALED = 0x00004000, - FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, - FLAG_LAYOUT_INSET_DECOR = 0x00010000, - FLAG_ALT_FOCUSABLE_IM = 0x00020000, - FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, - FLAG_SHOW_WHEN_LOCKED = 0x00080000, - FLAG_SHOW_WALLPAPER = 0x00100000, - FLAG_TURN_SCREEN_ON = 0x00200000, - FLAG_DISMISS_KEYGUARD = 0x00400000, - FLAG_SPLIT_TOUCH = 0x00800000, - FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000, - FLAG_COMPATIBLE_WINDOW = 0x20000000, - FLAG_SYSTEM_ERROR = 0x40000000, - }; - - // Window types from WindowManager.LayoutParams - enum { - FIRST_APPLICATION_WINDOW = 1, - TYPE_BASE_APPLICATION = 1, - TYPE_APPLICATION = 2, - TYPE_APPLICATION_STARTING = 3, - LAST_APPLICATION_WINDOW = 99, - FIRST_SUB_WINDOW = 1000, - TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, - TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, - TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, - TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, - TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, - LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, - TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, - TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, - TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, - TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, - TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, - TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, - TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, - TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, - TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, - TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, - TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, - TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, - TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, - TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+14, - TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, - TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, - TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+17, - LAST_SYSTEM_WINDOW = 2999, - }; - - sp<InputChannel> inputChannel; - String8 name; - int32_t layoutParamsFlags; - int32_t layoutParamsType; - nsecs_t dispatchingTimeout; - int32_t frameLeft; - int32_t frameTop; - int32_t frameRight; - int32_t frameBottom; - int32_t visibleFrameLeft; - int32_t visibleFrameTop; - int32_t visibleFrameRight; - int32_t visibleFrameBottom; - int32_t touchableAreaLeft; - int32_t touchableAreaTop; - int32_t touchableAreaRight; - int32_t touchableAreaBottom; - bool visible; - bool canReceiveKeys; - bool hasFocus; - bool hasWallpaper; - bool paused; - int32_t layer; - int32_t ownerPid; - int32_t ownerUid; - - bool touchableAreaContainsPoint(int32_t x, int32_t y) const; - bool frameContainsPoint(int32_t x, int32_t y) const; - - /* Returns true if the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool isTrustedOverlay() const; - - bool supportsSplitTouch() const; -}; - - -/* - * A private handle type used by the input manager to track the window. - */ -class InputApplicationHandle : public RefBase { -protected: - InputApplicationHandle() { } - virtual ~InputApplicationHandle() { } -}; - - -/* - * An input application describes properties of an application that can receive input. - */ -struct InputApplication { - String8 name; - nsecs_t dispatchingTimeout; - sp<InputApplicationHandle> handle; -}; - - -/* * Input dispatcher policy interface. * * The input reader policy is used by the input reader to interact with the Window Manager @@ -267,10 +139,10 @@ public: /* Notifies the system that an application is not responding. * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputChannel>& inputChannel) = 0; + const sp<InputWindowHandle>& inputWindowHandle) = 0; /* Notifies the system that an input channel is unrecoverably broken. */ - virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0; + virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0; /* Gets the key repeat initial timeout or -1 if automatic key repeating is disabled. */ virtual nsecs_t getKeyRepeatTimeout() = 0; @@ -303,12 +175,12 @@ public: 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, + virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) = 0; /* Allows the policy a chance to perform default processing for an unhandled key. * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */ - virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel, + virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0; /* Notifies the policy about switch events. @@ -407,7 +279,8 @@ public: * * These methods may be called on any thread (usually by the input manager). */ - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) = 0; + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle, bool monitor) = 0; virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; }; @@ -461,7 +334,8 @@ public: virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel, const sp<InputChannel>& toChannel); - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor); + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle, bool monitor); virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); private: @@ -615,6 +489,7 @@ private: KeyEntry* keyEntry; sp<InputChannel> inputChannel; sp<InputApplicationHandle> inputApplicationHandle; + sp<InputWindowHandle> inputWindowHandle; int32_t userActivityEventType; bool handled; }; @@ -815,7 +690,8 @@ private: }; Status status; - sp<InputChannel> inputChannel; + sp<InputChannel> inputChannel; // never null + sp<InputWindowHandle> inputWindowHandle; // may be null InputPublisher inputPublisher; InputState inputState; Queue<DispatchEntry> outboundQueue; @@ -823,7 +699,8 @@ private: nsecs_t lastEventTime; // the time when the event was originally captured nsecs_t lastDispatchTime; // the time when the last event was dispatched - explicit Connection(const sp<InputChannel>& inputChannel); + explicit Connection(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle); inline const char* getInputChannelName() const { return inputChannel->getName().string(); } @@ -851,6 +728,8 @@ private: DROP_REASON_POLICY = 1, DROP_REASON_APP_SWITCH = 2, DROP_REASON_DISABLED = 3, + DROP_REASON_BLOCKED = 4, + DROP_REASON_STALE = 5, }; sp<InputDispatcherPolicyInterface> mPolicy; @@ -884,6 +763,15 @@ private: bool isAppSwitchPendingLocked(); void resetPendingAppSwitchLocked(bool handled); + // Stale event latency optimization. + static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry); + + // Blocked event latency optimization. Drops old events when the user intends + // to transfer focus to a new application. + EventEntry* mNextUnblockedEvent; + + const InputWindow* findTouchedWindowAtLocked(int32_t x, int32_t y); + // All registered connections mapped by receive pipe file descriptor. KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd; @@ -1006,6 +894,7 @@ private: nsecs_t mInputTargetWaitStartTime; nsecs_t mInputTargetWaitTimeoutTime; bool mInputTargetWaitTimeoutExpired; + sp<InputApplicationHandle> mInputTargetWaitApplication; // Finding targets for input events. void resetTargetsLocked(); diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp new file mode 100644 index 000000000000..9ce45f50513c --- /dev/null +++ b/services/input/InputWindow.cpp @@ -0,0 +1,47 @@ +/* + * 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 "InputWindow" + +#include "InputWindow.h" + +#include <cutils/log.h> + +namespace android { + +// --- InputWindow --- + +bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const { + return x >= touchableAreaLeft && x <= touchableAreaRight + && y >= touchableAreaTop && y <= touchableAreaBottom; +} + +bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const { + return x >= frameLeft && x <= frameRight + && y >= frameTop && y <= frameBottom; +} + +bool InputWindow::isTrustedOverlay() const { + return layoutParamsType == TYPE_INPUT_METHOD + || layoutParamsType == TYPE_INPUT_METHOD_DIALOG + || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; +} + +bool InputWindow::supportsSplitTouch() const { + return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH; +} + +} // namespace android diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h new file mode 100644 index 000000000000..b3d5a651ba75 --- /dev/null +++ b/services/input/InputWindow.h @@ -0,0 +1,164 @@ +/* + * 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. + */ + +#ifndef _UI_INPUT_WINDOW_H +#define _UI_INPUT_WINDOW_H + +#include <ui/Input.h> +#include <ui/InputTransport.h> +#include <utils/RefBase.h> +#include <utils/Timers.h> +#include <utils/String8.h> + +#include "InputApplication.h" + +namespace android { + +/* + * A handle to a window that can receive input. + * Used by the native input dispatcher to indirectly refer to the window manager objects + * that describe a window. + */ +class InputWindowHandle : public RefBase { +protected: + InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) : + mInputApplicationHandle(inputApplicationHandle) { } + virtual ~InputWindowHandle() { } + +public: + inline sp<InputApplicationHandle> getInputApplicationHandle() { + return mInputApplicationHandle; + } + +private: + sp<InputApplicationHandle> mInputApplicationHandle; +}; + + +/* + * An input window describes the bounds of a window that can receive input. + */ +struct InputWindow { + // Window flags from WindowManager.LayoutParams + enum { + FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, + FLAG_DIM_BEHIND = 0x00000002, + FLAG_BLUR_BEHIND = 0x00000004, + FLAG_NOT_FOCUSABLE = 0x00000008, + FLAG_NOT_TOUCHABLE = 0x00000010, + FLAG_NOT_TOUCH_MODAL = 0x00000020, + FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, + FLAG_KEEP_SCREEN_ON = 0x00000080, + FLAG_LAYOUT_IN_SCREEN = 0x00000100, + FLAG_LAYOUT_NO_LIMITS = 0x00000200, + FLAG_FULLSCREEN = 0x00000400, + FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, + FLAG_DITHER = 0x00001000, + FLAG_SECURE = 0x00002000, + FLAG_SCALED = 0x00004000, + FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, + FLAG_LAYOUT_INSET_DECOR = 0x00010000, + FLAG_ALT_FOCUSABLE_IM = 0x00020000, + FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, + FLAG_SHOW_WHEN_LOCKED = 0x00080000, + FLAG_SHOW_WALLPAPER = 0x00100000, + FLAG_TURN_SCREEN_ON = 0x00200000, + FLAG_DISMISS_KEYGUARD = 0x00400000, + FLAG_SPLIT_TOUCH = 0x00800000, + FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000, + FLAG_COMPATIBLE_WINDOW = 0x20000000, + FLAG_SYSTEM_ERROR = 0x40000000, + }; + + // Window types from WindowManager.LayoutParams + enum { + FIRST_APPLICATION_WINDOW = 1, + TYPE_BASE_APPLICATION = 1, + TYPE_APPLICATION = 2, + TYPE_APPLICATION_STARTING = 3, + LAST_APPLICATION_WINDOW = 99, + FIRST_SUB_WINDOW = 1000, + TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, + TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, + TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, + TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, + TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, + LAST_SUB_WINDOW = 1999, + FIRST_SYSTEM_WINDOW = 2000, + TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, + TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, + TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, + TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, + TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, + TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, + TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, + TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, + TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, + TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, + TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, + TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, + TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, + TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, + TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+14, + TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, + TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, + TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+17, + LAST_SYSTEM_WINDOW = 2999, + }; + + sp<InputWindowHandle> inputWindowHandle; + sp<InputChannel> inputChannel; + String8 name; + int32_t layoutParamsFlags; + int32_t layoutParamsType; + nsecs_t dispatchingTimeout; + int32_t frameLeft; + int32_t frameTop; + int32_t frameRight; + int32_t frameBottom; + int32_t visibleFrameLeft; + int32_t visibleFrameTop; + int32_t visibleFrameRight; + int32_t visibleFrameBottom; + int32_t touchableAreaLeft; + int32_t touchableAreaTop; + int32_t touchableAreaRight; + int32_t touchableAreaBottom; + bool visible; + bool canReceiveKeys; + bool hasFocus; + bool hasWallpaper; + bool paused; + int32_t layer; + int32_t ownerPid; + int32_t ownerUid; + + bool touchableAreaContainsPoint(int32_t x, int32_t y) const; + bool frameContainsPoint(int32_t x, int32_t y) const; + + /* Returns true if the window is of a trusted type that is allowed to silently + * overlay other windows for the purpose of implementing the secure views feature. + * Trusted overlays, such as IME windows, can partly obscure other windows without causing + * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. + */ + bool isTrustedOverlay() const; + + bool supportsSplitTouch() const; +}; + +} // namespace android + +#endif // _UI_INPUT_WINDOW_H diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp index b79633ad5afe..5ba18671441e 100644 --- a/services/input/tests/InputDispatcher_test.cpp +++ b/services/input/tests/InputDispatcher_test.cpp @@ -36,11 +36,11 @@ private: } virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputChannel>& inputChannel) { + const sp<InputWindowHandle>& inputWindowHandle) { return 0; } - virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) { + virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) { } virtual nsecs_t getKeyRepeatTimeout() { @@ -61,12 +61,12 @@ private: virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { } - virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, + virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) { return false; } - virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel, + virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) { return false; } diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 9d2c52f07809..8ec6f534274d 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -368,7 +368,8 @@ private: return 0; } - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) { + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { ADD_FAILURE() << "Should never be called by input reader."; return 0; } diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java index 393beda35889..63be030b0556 100644 --- a/services/java/com/android/server/AccessibilityManagerService.java +++ b/services/java/com/android/server/AccessibilityManagerService.java @@ -532,7 +532,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub for (int i = 0, count = services.size(); i < count; i++) { Service service = services.get(i); - service.unbind(); + if (service.unbind()) { + i--; + count--; + } } } @@ -575,7 +578,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub Set<ComponentName> enabledServices) { Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap; - List<Service> services = mServices; boolean isEnabled = mIsEnabled; for (int i = 0, count = installedServices.size(); i < count; i++) { @@ -665,23 +667,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub /** * Binds to the accessibility service. + * + * @return True if binding is successful. */ - public void bind() { + public boolean bind() { if (mService == null) { - mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE); + return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE); } + return false; } /** * Unbinds form the accessibility service and removes it from the data * structures for service management. + * + * @return True if unbinding is successful. */ - public void unbind() { + public boolean unbind() { if (mService != null) { mContext.unbindService(this); mComponentNameToServiceMap.remove(mComponentName); mServices.remove(this); + return true; } + return false; } /** diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index ae408fccd8dc..22dd804f604b 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -144,6 +144,7 @@ class AppWidgetService extends IAppWidgetService.Stub // update the provider list. IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); mContext.registerReceiver(mBroadcastReceiver, filter); @@ -643,6 +644,12 @@ class AppWidgetService extends IAppWidgetService.Stub } boolean addProviderLocked(ResolveInfo ri) { + if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { + return false; + } + if (!ri.activityInfo.isEnabled()) { + return false; + } Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name), ri); if (p != null) { @@ -1160,6 +1167,7 @@ class AppWidgetService extends IAppWidgetService.Stub } } else { boolean added = false; + boolean changed = false; String pkgList[] = null; if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); @@ -1178,14 +1186,16 @@ class AppWidgetService extends IAppWidgetService.Stub } pkgList = new String[] { pkgName }; added = Intent.ACTION_PACKAGE_ADDED.equals(action); + changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); } if (pkgList == null || pkgList.length == 0) { return; } - if (added) { + if (added || changed) { synchronized (mAppWidgetIds) { Bundle extras = intent.getExtras(); - if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { + if (changed || (extras != null && + extras.getBoolean(Intent.EXTRA_REPLACING, false))) { for (String pkgName : pkgList) { // The package was just upgraded updateProvidersForPackageLocked(pkgName); diff --git a/services/java/com/android/server/InputApplication.java b/services/java/com/android/server/InputApplication.java index 38420d4f899f..ae0948441757 100644 --- a/services/java/com/android/server/InputApplication.java +++ b/services/java/com/android/server/InputApplication.java @@ -18,16 +18,19 @@ package com.android.server; /** * Describes input-related application properties for use by the input dispatcher. - * * @hide */ public final class InputApplication { + // Application handle. + public InputApplicationHandle inputApplicationHandle; + // Application name. public String name; - + // Dispatching timeout. public long dispatchingTimeoutNanos; - - // The application window token. - public Object token; + + public void recycle() { + inputApplicationHandle = null; + } } diff --git a/services/java/com/android/server/InputApplicationHandle.java b/services/java/com/android/server/InputApplicationHandle.java new file mode 100644 index 000000000000..d396d11caa41 --- /dev/null +++ b/services/java/com/android/server/InputApplicationHandle.java @@ -0,0 +1,45 @@ +/* + * 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; + +/** + * Functions as a handle for an application that can receive input. + * Enables the native input dispatcher to refer indirectly to the window manager's + * application window token. + * @hide + */ +public final class InputApplicationHandle { + // Pointer to the native input application handle. + // This field is lazily initialized via JNI. + @SuppressWarnings("unused") + private int ptr; + + // The window manager's application window token. + public final WindowManagerService.AppWindowToken appWindowToken; + + private native void nativeDispose(); + + public InputApplicationHandle(WindowManagerService.AppWindowToken appWindowToken) { + this.appWindowToken = appWindowToken; + } + + @Override + protected void finalize() throws Throwable { + nativeDispose(); + super.finalize(); + } +} diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index 410b8c259b00..5c2048bd81f4 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -77,7 +77,7 @@ public class InputManager { private static native boolean nativeHasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists); private static native void nativeRegisterInputChannel(InputChannel inputChannel, - boolean monitor); + InputWindowHandle inputWindowHandle, boolean monitor); private static native void nativeUnregisterInputChannel(InputChannel inputChannel); private static native int nativeInjectInputEvent(InputEvent event, int injectorPid, int injectorUid, int syncMode, int timeoutMillis); @@ -240,7 +240,7 @@ public class InputManager { } InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); - nativeRegisterInputChannel(inputChannels[0], true); + nativeRegisterInputChannel(inputChannels[0], null, true); inputChannels[0].dispose(); // don't need to retain the Java object reference return inputChannels[1]; } @@ -248,13 +248,16 @@ public class InputManager { /** * Registers an input channel so that it can be used as an input event target. * @param inputChannel The input channel to register. + * @param inputWindowHandle The handle of the input window associated with the + * input channel, or null if none. */ - public void registerInputChannel(InputChannel inputChannel) { + public void registerInputChannel(InputChannel inputChannel, + InputWindowHandle inputWindowHandle) { if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null."); } - nativeRegisterInputChannel(inputChannel, false); + nativeRegisterInputChannel(inputChannel, inputWindowHandle, false); } /** @@ -429,13 +432,15 @@ public class InputManager { } @SuppressWarnings("unused") - public void notifyInputChannelBroken(InputChannel inputChannel) { - mWindowManagerService.mInputMonitor.notifyInputChannelBroken(inputChannel); + public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { + mWindowManagerService.mInputMonitor.notifyInputChannelBroken(inputWindowHandle); } @SuppressWarnings("unused") - public long notifyANR(Object token, InputChannel inputChannel) { - return mWindowManagerService.mInputMonitor.notifyANR(token, inputChannel); + public long notifyANR(InputApplicationHandle inputApplicationHandle, + InputWindowHandle inputWindowHandle) { + return mWindowManagerService.mInputMonitor.notifyANR( + inputApplicationHandle, inputWindowHandle); } @SuppressWarnings("unused") @@ -445,14 +450,14 @@ public class InputManager { } @SuppressWarnings("unused") - public boolean interceptKeyBeforeDispatching(InputChannel focus, + public boolean interceptKeyBeforeDispatching(InputWindowHandle focus, KeyEvent event, int policyFlags) { return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching( focus, event, policyFlags); } @SuppressWarnings("unused") - public KeyEvent dispatchUnhandledKey(InputChannel focus, + public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, KeyEvent event, int policyFlags) { return mWindowManagerService.mInputMonitor.dispatchUnhandledKey( focus, event, policyFlags); diff --git a/services/java/com/android/server/InputWindow.java b/services/java/com/android/server/InputWindow.java index befc770b4136..1515290145d8 100644 --- a/services/java/com/android/server/InputWindow.java +++ b/services/java/com/android/server/InputWindow.java @@ -20,64 +20,67 @@ import android.view.InputChannel; /** * Describes input-related window properties for use by the input dispatcher. - * * @hide */ public final class InputWindow { + // The window handle. + public InputWindowHandle inputWindowHandle; + // The input channel associated with the window. public InputChannel inputChannel; - + // The window name. public String name; - + // Window layout params attributes. (WindowManager.LayoutParams) public int layoutParamsFlags; public int layoutParamsType; - + // Dispatching timeout. public long dispatchingTimeoutNanos; - + // Window frame area. public int frameLeft; public int frameTop; public int frameRight; public int frameBottom; - + // Window visible frame area. public int visibleFrameLeft; public int visibleFrameTop; public int visibleFrameRight; public int visibleFrameBottom; - + // Window touchable area. public int touchableAreaLeft; public int touchableAreaTop; public int touchableAreaRight; public int touchableAreaBottom; - + // Window is visible. public boolean visible; - + // Window can receive keys. public boolean canReceiveKeys; - + // Window has focus. public boolean hasFocus; - + // Window has wallpaper. (window is the current wallpaper target) public boolean hasWallpaper; - + // Input event dispatching is paused. public boolean paused; - + // Window layer. public int layer; - + // Id of process and user that owns the window. public int ownerPid; public int ownerUid; - + public void recycle() { + inputWindowHandle = null; inputChannel = null; } } diff --git a/services/java/com/android/server/InputWindowHandle.java b/services/java/com/android/server/InputWindowHandle.java new file mode 100644 index 000000000000..4b9293918031 --- /dev/null +++ b/services/java/com/android/server/InputWindowHandle.java @@ -0,0 +1,51 @@ +/* + * 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; + +import android.view.WindowManagerPolicy; + +/** + * Functions as a handle for a window that can receive input. + * Enables the native input dispatcher to refer indirectly to the window manager's window state. + * @hide + */ +public final class InputWindowHandle { + // Pointer to the native input window handle. + // This field is lazily initialized via JNI. + @SuppressWarnings("unused") + private int ptr; + + // The input application handle. + public final InputApplicationHandle inputApplicationHandle; + + // The window manager's window state. + public final WindowManagerPolicy.WindowState windowState; + + private native void nativeDispose(); + + public InputWindowHandle(InputApplicationHandle inputApplicationHandle, + WindowManagerPolicy.WindowState windowState) { + this.inputApplicationHandle = inputApplicationHandle; + this.windowState = windowState; + } + + @Override + protected void finalize() throws Throwable { + nativeDispose(); + super.finalize(); + } +} diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index c33d19d706a7..5c823bae8aa4 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -536,7 +536,7 @@ public class WindowManagerService extends IWindowManager.Stub InputChannel[] channels = InputChannel.openInputChannelPair("drag"); mServerChannel = channels[0]; mClientChannel = channels[1]; - mInputManager.registerInputChannel(mServerChannel); + mInputManager.registerInputChannel(mServerChannel, null); InputQueue.registerInputChannel(mClientChannel, mDragInputHandler, mH.getLooper().getQueue()); } @@ -2311,7 +2311,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mInputChannel = inputChannels[0]; inputChannels[1].transferToBinderOutParameter(outInputChannel); - mInputManager.registerInputChannel(win.mInputChannel); + mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle); } // From now on, no exceptions or errors allowed! @@ -5711,13 +5711,13 @@ public class WindowManagerService extends IWindowManager.Stub * * Called by the InputManager. */ - public void notifyInputChannelBroken(InputChannel inputChannel) { + public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { + if (inputWindowHandle == null) { + return; + } + synchronized (mWindowMap) { - WindowState windowState = getWindowStateForInputChannelLocked(inputChannel); - if (windowState == null) { - return; // irrelevant - } - + WindowState windowState = (WindowState) inputWindowHandle.windowState; Slog.i(TAG, "WINDOW DIED " + windowState); removeWindowLocked(windowState.mSession, windowState); } @@ -5728,11 +5728,12 @@ public class WindowManagerService extends IWindowManager.Stub * * Called by the InputManager. */ - public long notifyANR(Object token, InputChannel inputChannel) { + public long notifyANR(InputApplicationHandle inputApplicationHandle, + InputWindowHandle inputWindowHandle) { AppWindowToken appWindowToken = null; - if (inputChannel != null) { + if (inputWindowHandle != null) { synchronized (mWindowMap) { - WindowState windowState = getWindowStateForInputChannelLocked(inputChannel); + WindowState windowState = (WindowState) inputWindowHandle.windowState; if (windowState != null) { Slog.i(TAG, "Input event dispatching timed out sending to " + windowState.mAttrs.getTitle()); @@ -5741,8 +5742,8 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (appWindowToken == null && token != null) { - appWindowToken = (AppWindowToken) token; + if (appWindowToken == null && inputApplicationHandle != null) { + appWindowToken = inputApplicationHandle.appWindowToken; Slog.i(TAG, "Input event dispatching timed out sending to application " + appWindowToken.stringName); } @@ -5762,24 +5763,6 @@ public class WindowManagerService extends IWindowManager.Stub } return 0; // abort dispatching } - - private WindowState getWindowStateForInputChannel(InputChannel inputChannel) { - synchronized (mWindowMap) { - return getWindowStateForInputChannelLocked(inputChannel); - } - } - - private WindowState getWindowStateForInputChannelLocked(InputChannel inputChannel) { - int windowCount = mWindows.size(); - for (int i = 0; i < windowCount; i++) { - WindowState windowState = mWindows.get(i); - if (windowState.mInputChannel == inputChannel) { - return windowState; - } - } - - return null; - } private void addDragInputWindowLw(InputWindowList windowList) { final InputWindow inputWindow = windowList.add(); @@ -5856,6 +5839,7 @@ public class WindowManagerService extends IWindowManager.Stub // Add a window to our list of input windows. final InputWindow inputWindow = mTempInputWindows.add(); + inputWindow.inputWindowHandle = child.mInputWindowHandle; inputWindow.inputChannel = child.mInputChannel; inputWindow.name = child.toString(); inputWindow.layoutParamsFlags = flags; @@ -5934,16 +5918,16 @@ public class WindowManagerService extends IWindowManager.Stub /* Provides an opportunity for the window manager policy to process a key before * ordinary dispatch. */ public boolean interceptKeyBeforeDispatching( - InputChannel focus, KeyEvent event, int policyFlags) { - WindowState windowState = getWindowStateForInputChannel(focus); + InputWindowHandle focus, KeyEvent event, int policyFlags) { + WindowState windowState = (WindowState) focus.windowState; return mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags); } /* Provides an opportunity for the window manager policy to process a key that * the application did not handle. */ public KeyEvent dispatchUnhandledKey( - InputChannel focus, KeyEvent event, int policyFlags) { - WindowState windowState = getWindowStateForInputChannel(focus); + InputWindowHandle focus, KeyEvent event, int policyFlags) { + WindowState windowState = (WindowState) focus.windowState; return mPolicy.dispatchUnhandledKey(windowState, event, policyFlags); } @@ -5973,12 +5957,14 @@ public class WindowManagerService extends IWindowManager.Stub if (newApp == null) { mInputManager.setFocusedApplication(null); } else { + mTempInputApplication.inputApplicationHandle = newApp.mInputApplicationHandle; mTempInputApplication.name = newApp.toString(); mTempInputApplication.dispatchingTimeoutNanos = newApp.inputDispatchingTimeoutNanos; - mTempInputApplication.token = newApp; - + mInputManager.setFocusedApplication(mTempInputApplication); + + mTempInputApplication.recycle(); } } @@ -6823,7 +6809,8 @@ public class WindowManagerService extends IWindowManager.Stub int mSurfaceLayer; float mSurfaceAlpha; - // Input channel + // Input channel and input window handle used by the input dispatcher. + InputWindowHandle mInputWindowHandle; InputChannel mInputChannel; // Used to improve performance of toString() @@ -6915,6 +6902,8 @@ public class WindowManagerService extends IWindowManager.Stub mLayer = 0; mAnimLayer = 0; mLastLayer = 0; + mInputWindowHandle = new InputWindowHandle( + mAppToken != null ? mAppToken.mInputApplicationHandle : null, this); } void attach() { @@ -8304,11 +8293,15 @@ public class WindowManagerService extends IWindowManager.Stub boolean startingMoved; boolean firstWindowDrawn; + // Input application handle used by the input dispatcher. + InputApplicationHandle mInputApplicationHandle; + AppWindowToken(IApplicationToken _token) { super(_token.asBinder(), WindowManager.LayoutParams.TYPE_APPLICATION, true); appWindowToken = this; appToken = _token; + mInputApplicationHandle = new InputApplicationHandle(this); } public void setAnimation(Animation anim) { diff --git a/services/jni/Android.mk b/services/jni/Android.mk index ec85e54b52c2..f5a5b4da5e80 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -4,7 +4,11 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ com_android_server_AlarmManagerService.cpp \ com_android_server_BatteryService.cpp \ + com_android_server_InputApplication.cpp \ + com_android_server_InputApplicationHandle.cpp \ com_android_server_InputManager.cpp \ + com_android_server_InputWindow.cpp \ + com_android_server_InputWindowHandle.cpp \ com_android_server_LightsService.cpp \ com_android_server_PowerManagerService.cpp \ com_android_server_SystemServer.cpp \ diff --git a/services/jni/com_android_server_InputApplication.cpp b/services/jni/com_android_server_InputApplication.cpp new file mode 100644 index 000000000000..a46a162071e8 --- /dev/null +++ b/services/jni/com_android_server_InputApplication.cpp @@ -0,0 +1,95 @@ +/* + * 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 "InputApplication" + +#include "JNIHelp.h" +#include "jni.h" +#include <android_runtime/AndroidRuntime.h> + +#include "com_android_server_InputApplication.h" +#include "com_android_server_InputApplicationHandle.h" + +namespace android { + +static struct { + jclass clazz; + + jfieldID inputApplicationHandle; + jfieldID name; + jfieldID dispatchingTimeoutNanos; +} gInputApplicationClassInfo; + + +// --- Global functions --- + +void android_server_InputApplication_toNative( + JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication) { + jobject inputApplicationHandleObj = env->GetObjectField(inputApplicationObj, + gInputApplicationClassInfo.inputApplicationHandle); + if (inputApplicationHandleObj) { + outInputApplication->inputApplicationHandle = + android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj); + env->DeleteLocalRef(inputApplicationHandleObj); + } else { + outInputApplication->inputApplicationHandle = NULL; + } + + jstring nameObj = jstring(env->GetObjectField(inputApplicationObj, + gInputApplicationClassInfo.name)); + if (nameObj) { + const char* nameStr = env->GetStringUTFChars(nameObj, NULL); + outInputApplication->name.setTo(nameStr); + env->ReleaseStringUTFChars(nameObj, nameStr); + env->DeleteLocalRef(nameObj); + } else { + LOGE("InputApplication.name should not be null."); + outInputApplication->name.setTo("unknown"); + } + + outInputApplication->dispatchingTimeout = env->GetLongField(inputApplicationObj, + gInputApplicationClassInfo.dispatchingTimeoutNanos); +} + + +// --- JNI --- + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + +int register_android_server_InputApplication(JNIEnv* env) { + FIND_CLASS(gInputApplicationClassInfo.clazz, "com/android/server/InputApplication"); + + GET_FIELD_ID(gInputApplicationClassInfo.inputApplicationHandle, + gInputApplicationClassInfo.clazz, + "inputApplicationHandle", "Lcom/android/server/InputApplicationHandle;"); + + GET_FIELD_ID(gInputApplicationClassInfo.name, gInputApplicationClassInfo.clazz, + "name", "Ljava/lang/String;"); + + GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos, + gInputApplicationClassInfo.clazz, + "dispatchingTimeoutNanos", "J"); + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_InputApplication.h b/services/jni/com_android_server_InputApplication.h new file mode 100644 index 000000000000..85fb891cfd2b --- /dev/null +++ b/services/jni/com_android_server_InputApplication.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef _ANDROID_SERVER_INPUT_APPLICATION_H +#define _ANDROID_SERVER_INPUT_APPLICATION_H + +#include <input/InputApplication.h> + +#include "JNIHelp.h" +#include "jni.h" + +namespace android { + +extern void android_server_InputApplication_toNative( + JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication); + +} // namespace android + +#endif // _ANDROID_SERVER_INPUT_APPLICATION_H diff --git a/services/jni/com_android_server_InputApplicationHandle.cpp b/services/jni/com_android_server_InputApplicationHandle.cpp new file mode 100644 index 000000000000..ab82635595d8 --- /dev/null +++ b/services/jni/com_android_server_InputApplicationHandle.cpp @@ -0,0 +1,121 @@ +/* + * 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 "InputApplicationHandle" + +#include "JNIHelp.h" +#include "jni.h" +#include <android_runtime/AndroidRuntime.h> +#include <utils/threads.h> + +#include "com_android_server_InputApplicationHandle.h" + +namespace android { + +static struct { + jclass clazz; + + jfieldID ptr; +} gInputApplicationHandleClassInfo; + +static Mutex gHandleMutex; + + +// --- NativeInputApplicationHandle --- + +NativeInputApplicationHandle::NativeInputApplicationHandle(jweak objWeak) : + mObjWeak(objWeak) { +} + +NativeInputApplicationHandle::~NativeInputApplicationHandle() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->DeleteWeakGlobalRef(mObjWeak); +} + +jobject NativeInputApplicationHandle::getInputApplicationHandleObjLocalRef(JNIEnv* env) { + return env->NewLocalRef(mObjWeak); +} + + +// --- Global functions --- + +sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle( + JNIEnv* env, jobject inputApplicationHandleObj) { + if (!inputApplicationHandleObj) { + return NULL; + } + + AutoMutex _l(gHandleMutex); + + int ptr = env->GetIntField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr); + NativeInputApplicationHandle* handle; + if (ptr) { + handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr); + } else { + jweak objWeak = env->NewWeakGlobalRef(inputApplicationHandleObj); + handle = new NativeInputApplicationHandle(objWeak); + handle->incStrong(inputApplicationHandleObj); + env->SetIntField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr, + reinterpret_cast<int>(handle)); + } + return handle; +} + + +// --- JNI --- + +static void android_server_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) { + AutoMutex _l(gHandleMutex); + + int ptr = env->GetIntField(obj, gInputApplicationHandleClassInfo.ptr); + if (ptr) { + env->SetIntField(obj, gInputApplicationHandleClassInfo.ptr, 0); + + NativeInputApplicationHandle* handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr); + handle->decStrong(obj); + } +} + + +static JNINativeMethod gInputApplicationHandleMethods[] = { + /* name, signature, funcPtr */ + { "nativeDispose", "()V", + (void*) android_server_InputApplicationHandle_nativeDispose }, +}; + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + +int register_android_server_InputApplicationHandle(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "com/android/server/InputApplicationHandle", + gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + FIND_CLASS(gInputApplicationHandleClassInfo.clazz, "com/android/server/InputApplicationHandle"); + + GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, gInputApplicationHandleClassInfo.clazz, + "ptr", "I"); + + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_InputApplicationHandle.h b/services/jni/com_android_server_InputApplicationHandle.h new file mode 100644 index 000000000000..9d187219b2ec --- /dev/null +++ b/services/jni/com_android_server_InputApplicationHandle.h @@ -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. + */ + +#ifndef _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H +#define _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H + +#include <input/InputApplication.h> + +#include "JNIHelp.h" +#include "jni.h" + +namespace android { + +class NativeInputApplicationHandle : public InputApplicationHandle { +public: + NativeInputApplicationHandle(jweak objWeak); + virtual ~NativeInputApplicationHandle(); + + jobject getInputApplicationHandleObjLocalRef(JNIEnv* env); + +private: + jweak mObjWeak; +}; + + +extern sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle( + JNIEnv* env, jobject inputApplicationHandleObj); + +} // namespace android + +#endif // _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 5ed63f0b14dc..e04e4c3324f3 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -42,11 +42,13 @@ #include <android/graphics/GraphicsJNI.h> #include "com_android_server_PowerManagerService.h" +#include "com_android_server_InputApplication.h" +#include "com_android_server_InputApplicationHandle.h" +#include "com_android_server_InputWindow.h" +#include "com_android_server_InputWindowHandle.h" namespace android { -// ---------------------------------------------------------------------------- - static struct { jclass clazz; @@ -68,44 +70,6 @@ static struct { static struct { jclass clazz; - - jfieldID inputChannel; - jfieldID name; - jfieldID layoutParamsFlags; - jfieldID layoutParamsType; - jfieldID dispatchingTimeoutNanos; - jfieldID frameLeft; - jfieldID frameTop; - jfieldID frameRight; - jfieldID frameBottom; - jfieldID visibleFrameLeft; - jfieldID visibleFrameTop; - jfieldID visibleFrameRight; - jfieldID visibleFrameBottom; - jfieldID touchableAreaLeft; - jfieldID touchableAreaTop; - jfieldID touchableAreaRight; - jfieldID touchableAreaBottom; - jfieldID visible; - jfieldID canReceiveKeys; - jfieldID hasFocus; - jfieldID hasWallpaper; - jfieldID paused; - jfieldID layer; - jfieldID ownerPid; - jfieldID ownerUid; -} gInputWindowClassInfo; - -static struct { - jclass clazz; - - jfieldID name; - jfieldID dispatchingTimeoutNanos; - jfieldID token; -} gInputApplicationClassInfo; - -static struct { - jclass clazz; } gKeyEventClassInfo; static struct { @@ -141,7 +105,29 @@ static struct { jfieldID hotSpotY; } gPointerIconClassInfo; -// ---------------------------------------------------------------------------- + +// --- Global functions --- + +static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env, + const sp<InputApplicationHandle>& inputApplicationHandle) { + if (inputApplicationHandle == NULL) { + return NULL; + } + return static_cast<NativeInputApplicationHandle*>(inputApplicationHandle.get())-> + getInputApplicationHandleObjLocalRef(env); +} + +static jobject getInputWindowHandleObjLocalRef(JNIEnv* env, + const sp<InputWindowHandle>& inputWindowHandle) { + if (inputWindowHandle == NULL) { + return NULL; + } + return static_cast<NativeInputWindowHandle*>(inputWindowHandle.get())-> + getInputWindowHandleObjLocalRef(env); +} + + +// --- NativeInputManager --- class NativeInputManager : public virtual RefBase, public virtual InputReaderPolicyInterface, @@ -160,7 +146,7 @@ public: void setDisplayOrientation(int32_t displayId, int32_t orientation); status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel, - jweak inputChannelObjWeak, bool monitor); + const sp<InputWindowHandle>& inputWindowHandle, bool monitor); status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel); void setInputWindows(JNIEnv* env, jobjectArray windowObjArray); @@ -182,37 +168,22 @@ public: uint32_t policyFlags); virtual void notifyConfigurationChanged(nsecs_t when); virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputChannel>& inputChannel); - virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel); + const sp<InputWindowHandle>& inputWindowHandle); + virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle); virtual nsecs_t getKeyRepeatTimeout(); virtual nsecs_t getKeyRepeatDelay(); virtual int32_t getMaxEventsPerSecond(); virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags); virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags); - virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, + virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags); - virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel, + virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent); virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType); virtual bool checkInjectEventsPermissionNonReentrant( int32_t injectorPid, int32_t injectorUid); private: - class ApplicationToken : public InputApplicationHandle { - jweak mTokenObjWeak; - - public: - ApplicationToken(jweak tokenObjWeak) : - mTokenObjWeak(tokenObjWeak) { } - - virtual ~ApplicationToken() { - JNIEnv* env = NativeInputManager::jniEnv(); - env->DeleteWeakGlobalRef(mTokenObjWeak); - } - - inline jweak getTokenObj() { return mTokenObjWeak; } - }; - sp<InputManager> mInputManager; jobject mCallbacksObj; @@ -232,19 +203,12 @@ private: // Pointer controller singleton, created and destroyed as needed. wp<PointerController> pointerController; - - // Weak references to all currently registered input channels by connection pointer. - KeyedVector<InputChannel*, jweak> inputChannelObjWeakTable; } mLocked; // Power manager interactions. bool isScreenOn(); bool isScreenBright(); - jobject getInputChannelObjLocal(JNIEnv* env, const sp<InputChannel>& inputChannel); - - static bool populateWindow(JNIEnv* env, jobject windowObj, InputWindow& outWindow); - static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName); static inline JNIEnv* jniEnv() { @@ -252,7 +216,7 @@ private: } }; -// ---------------------------------------------------------------------------- + NativeInputManager::NativeInputManager(jobject callbacksObj) : mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), @@ -328,88 +292,17 @@ void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orient } status_t NativeInputManager::registerInputChannel(JNIEnv* env, - const sp<InputChannel>& inputChannel, jobject inputChannelObj, bool monitor) { - jweak inputChannelObjWeak = env->NewWeakGlobalRef(inputChannelObj); - if (! inputChannelObjWeak) { - LOGE("Could not create weak reference for input channel."); - LOGE_EX(env); - return NO_MEMORY; - } - - status_t status; - { - AutoMutex _l(mLock); - - ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannel.get()); - if (index >= 0) { - LOGE("Input channel object '%s' has already been registered", - inputChannel->getName().string()); - status = INVALID_OPERATION; - goto DeleteWeakRef; - } - - mLocked.inputChannelObjWeakTable.add(inputChannel.get(), inputChannelObjWeak); - } - - status = mInputManager->getDispatcher()->registerInputChannel(inputChannel, monitor); - if (! status) { - // Success. - return OK; - } - - // Failed! - { - AutoMutex _l(mLock); - mLocked.inputChannelObjWeakTable.removeItem(inputChannel.get()); - } - -DeleteWeakRef: - env->DeleteWeakGlobalRef(inputChannelObjWeak); - return status; + const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { + return mInputManager->getDispatcher()->registerInputChannel( + inputChannel, inputWindowHandle, monitor); } status_t NativeInputManager::unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel) { - jweak inputChannelObjWeak; - { - AutoMutex _l(mLock); - - ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannel.get()); - if (index < 0) { - LOGE("Input channel object '%s' is not currently registered", - inputChannel->getName().string()); - return INVALID_OPERATION; - } - - inputChannelObjWeak = mLocked.inputChannelObjWeakTable.valueAt(index); - mLocked.inputChannelObjWeakTable.removeItemsAt(index); - } - - env->DeleteWeakGlobalRef(inputChannelObjWeak); - return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel); } -jobject NativeInputManager::getInputChannelObjLocal(JNIEnv* env, - const sp<InputChannel>& inputChannel) { - InputChannel* inputChannelPtr = inputChannel.get(); - if (! inputChannelPtr) { - return NULL; - } - - { - AutoMutex _l(mLock); - - ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannelPtr); - if (index < 0) { - return NULL; - } - - jweak inputChannelObjWeak = mLocked.inputChannelObjWeakTable.valueAt(index); - return env->NewLocalRef(inputChannelObjWeak); - } -} - bool NativeInputManager::getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation) { bool result = false; @@ -549,50 +442,46 @@ void NativeInputManager::notifyConfigurationChanged(nsecs_t when) { } nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputChannel>& inputChannel) { + const sp<InputWindowHandle>& inputWindowHandle) { #if DEBUG_INPUT_DISPATCHER_POLICY LOGD("notifyANR"); #endif JNIEnv* env = jniEnv(); - jobject tokenObjLocal; - if (inputApplicationHandle.get()) { - ApplicationToken* token = static_cast<ApplicationToken*>(inputApplicationHandle.get()); - jweak tokenObjWeak = token->getTokenObj(); - tokenObjLocal = env->NewLocalRef(tokenObjWeak); - } else { - tokenObjLocal = NULL; - } + jobject inputApplicationHandleObj = + getInputApplicationHandleObjLocalRef(env, inputApplicationHandle); + jobject inputWindowHandleObj = + getInputWindowHandleObjLocalRef(env, inputWindowHandle); - jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel); jlong newTimeout = env->CallLongMethod(mCallbacksObj, - gCallbacksClassInfo.notifyANR, tokenObjLocal, inputChannelObjLocal); + gCallbacksClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj); if (checkAndClearExceptionFromCallback(env, "notifyANR")) { newTimeout = 0; // abort dispatch } else { assert(newTimeout >= 0); } - env->DeleteLocalRef(tokenObjLocal); - env->DeleteLocalRef(inputChannelObjLocal); + env->DeleteLocalRef(inputWindowHandleObj); + env->DeleteLocalRef(inputApplicationHandleObj); return newTimeout; } -void NativeInputManager::notifyInputChannelBroken(const sp<InputChannel>& inputChannel) { +void NativeInputManager::notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) { #if DEBUG_INPUT_DISPATCHER_POLICY - LOGD("notifyInputChannelBroken - inputChannel='%s'", inputChannel->getName().string()); + LOGD("notifyInputChannelBroken"); #endif JNIEnv* env = jniEnv(); - jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel); - if (inputChannelObjLocal) { + jobject inputWindowHandleObj = + getInputWindowHandleObjLocalRef(env, inputWindowHandle); + if (inputWindowHandleObj) { env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyInputChannelBroken, - inputChannelObjLocal); + inputWindowHandleObj); checkAndClearExceptionFromCallback(env, "notifyInputChannelBroken"); - env->DeleteLocalRef(inputChannelObjLocal); + env->DeleteLocalRef(inputWindowHandleObj); } } @@ -630,160 +519,32 @@ void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArra jsize length = env->GetArrayLength(windowObjArray); for (jsize i = 0; i < length; i++) { - jobject inputTargetObj = env->GetObjectArrayElement(windowObjArray, i); - if (! inputTargetObj) { + jobject windowObj = env->GetObjectArrayElement(windowObjArray, i); + if (! windowObj) { break; // found null element indicating end of used portion of the array } windows.push(); InputWindow& window = windows.editTop(); - bool valid = populateWindow(env, inputTargetObj, window); - if (! valid) { + android_server_InputWindow_toNative(env, windowObj, &window); + if (window.inputChannel == NULL) { windows.pop(); } - - env->DeleteLocalRef(inputTargetObj); + env->DeleteLocalRef(windowObj); } mInputManager->getDispatcher()->setInputWindows(windows); } -bool NativeInputManager::populateWindow(JNIEnv* env, jobject windowObj, - InputWindow& outWindow) { - bool valid = false; - - jobject inputChannelObj = env->GetObjectField(windowObj, - gInputWindowClassInfo.inputChannel); - if (inputChannelObj) { - sp<InputChannel> inputChannel = - android_view_InputChannel_getInputChannel(env, inputChannelObj); - if (inputChannel != NULL) { - jstring name = jstring(env->GetObjectField(windowObj, - gInputWindowClassInfo.name)); - jint layoutParamsFlags = env->GetIntField(windowObj, - gInputWindowClassInfo.layoutParamsFlags); - jint layoutParamsType = env->GetIntField(windowObj, - gInputWindowClassInfo.layoutParamsType); - jlong dispatchingTimeoutNanos = env->GetLongField(windowObj, - gInputWindowClassInfo.dispatchingTimeoutNanos); - jint frameLeft = env->GetIntField(windowObj, - gInputWindowClassInfo.frameLeft); - jint frameTop = env->GetIntField(windowObj, - gInputWindowClassInfo.frameTop); - jint frameRight = env->GetIntField(windowObj, - gInputWindowClassInfo.frameRight); - jint frameBottom = env->GetIntField(windowObj, - gInputWindowClassInfo.frameBottom); - jint visibleFrameLeft = env->GetIntField(windowObj, - gInputWindowClassInfo.visibleFrameLeft); - jint visibleFrameTop = env->GetIntField(windowObj, - gInputWindowClassInfo.visibleFrameTop); - jint visibleFrameRight = env->GetIntField(windowObj, - gInputWindowClassInfo.visibleFrameRight); - jint visibleFrameBottom = env->GetIntField(windowObj, - gInputWindowClassInfo.visibleFrameBottom); - jint touchableAreaLeft = env->GetIntField(windowObj, - gInputWindowClassInfo.touchableAreaLeft); - jint touchableAreaTop = env->GetIntField(windowObj, - gInputWindowClassInfo.touchableAreaTop); - jint touchableAreaRight = env->GetIntField(windowObj, - gInputWindowClassInfo.touchableAreaRight); - jint touchableAreaBottom = env->GetIntField(windowObj, - gInputWindowClassInfo.touchableAreaBottom); - jboolean visible = env->GetBooleanField(windowObj, - gInputWindowClassInfo.visible); - jboolean canReceiveKeys = env->GetBooleanField(windowObj, - gInputWindowClassInfo.canReceiveKeys); - jboolean hasFocus = env->GetBooleanField(windowObj, - gInputWindowClassInfo.hasFocus); - jboolean hasWallpaper = env->GetBooleanField(windowObj, - gInputWindowClassInfo.hasWallpaper); - jboolean paused = env->GetBooleanField(windowObj, - gInputWindowClassInfo.paused); - jint layer = env->GetIntField(windowObj, - gInputWindowClassInfo.layer); - jint ownerPid = env->GetIntField(windowObj, - gInputWindowClassInfo.ownerPid); - jint ownerUid = env->GetIntField(windowObj, - gInputWindowClassInfo.ownerUid); - - const char* nameStr = env->GetStringUTFChars(name, NULL); - - outWindow.inputChannel = inputChannel; - outWindow.name.setTo(nameStr); - outWindow.layoutParamsFlags = layoutParamsFlags; - outWindow.layoutParamsType = layoutParamsType; - outWindow.dispatchingTimeout = dispatchingTimeoutNanos; - outWindow.frameLeft = frameLeft; - outWindow.frameTop = frameTop; - outWindow.frameRight = frameRight; - outWindow.frameBottom = frameBottom; - outWindow.visibleFrameLeft = visibleFrameLeft; - outWindow.visibleFrameTop = visibleFrameTop; - outWindow.visibleFrameRight = visibleFrameRight; - outWindow.visibleFrameBottom = visibleFrameBottom; - outWindow.touchableAreaLeft = touchableAreaLeft; - outWindow.touchableAreaTop = touchableAreaTop; - outWindow.touchableAreaRight = touchableAreaRight; - outWindow.touchableAreaBottom = touchableAreaBottom; - outWindow.visible = visible; - outWindow.canReceiveKeys = canReceiveKeys; - outWindow.hasFocus = hasFocus; - outWindow.hasWallpaper = hasWallpaper; - outWindow.paused = paused; - outWindow.layer = layer; - outWindow.ownerPid = ownerPid; - outWindow.ownerUid = ownerUid; - - env->ReleaseStringUTFChars(name, nameStr); - env->DeleteLocalRef(name); - valid = true; - } else { - LOGW("Dropping input target because its input channel is not initialized."); - } - - env->DeleteLocalRef(inputChannelObj); - } else { - LOGW("Dropping input target because the input channel object was null."); - } - return valid; -} - void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationObj) { if (applicationObj) { - jstring nameObj = jstring(env->GetObjectField(applicationObj, - gInputApplicationClassInfo.name)); - jlong dispatchingTimeoutNanos = env->GetLongField(applicationObj, - gInputApplicationClassInfo.dispatchingTimeoutNanos); - jobject tokenObj = env->GetObjectField(applicationObj, - gInputApplicationClassInfo.token); - jweak tokenObjWeak = env->NewWeakGlobalRef(tokenObj); - if (! tokenObjWeak) { - LOGE("Could not create weak reference for application token."); - LOGE_EX(env); - env->ExceptionClear(); - } - env->DeleteLocalRef(tokenObj); - - String8 name; - if (nameObj) { - const char* nameStr = env->GetStringUTFChars(nameObj, NULL); - name.setTo(nameStr); - env->ReleaseStringUTFChars(nameObj, nameStr); - env->DeleteLocalRef(nameObj); - } else { - LOGE("InputApplication.name should not be null."); - name.setTo("unknown"); - } - InputApplication application; - application.name = name; - application.dispatchingTimeout = dispatchingTimeoutNanos; - application.handle = new ApplicationToken(tokenObjWeak); - mInputManager->getDispatcher()->setFocusedApplication(& application); - } else { - mInputManager->getDispatcher()->setFocusedApplication(NULL); + android_server_InputApplication_toNative(env, applicationObj, &application); + if (application.inputApplicationHandle != NULL) { + mInputManager->getDispatcher()->setFocusedApplication(&application); + } } + mInputManager->getDispatcher()->setFocusedApplication(NULL); } void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) { @@ -875,7 +636,8 @@ void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& } } -bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, +bool NativeInputManager::interceptKeyBeforeDispatching( + const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) { // Policy: // - Ignore untrusted events and pass them along. @@ -885,13 +647,13 @@ bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& i if (policyFlags & POLICY_FLAG_TRUSTED) { JNIEnv* env = jniEnv(); - // Note: inputChannel may be null. - jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel); + // Note: inputWindowHandle may be null. + jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle); jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); if (keyEventObj) { jboolean consumed = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.interceptKeyBeforeDispatching, - inputChannelObj, keyEventObj, policyFlags); + inputWindowHandleObj, keyEventObj, policyFlags); bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching"); android_view_KeyEvent_recycle(env, keyEventObj); env->DeleteLocalRef(keyEventObj); @@ -899,12 +661,12 @@ bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& i } else { LOGE("Failed to obtain key event object for interceptKeyBeforeDispatching."); } - env->DeleteLocalRef(inputChannelObj); + env->DeleteLocalRef(inputWindowHandleObj); } return result; } -bool NativeInputManager::dispatchUnhandledKey(const sp<InputChannel>& inputChannel, +bool NativeInputManager::dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) { // Policy: // - Ignore untrusted events and do not perform default handling. @@ -912,13 +674,13 @@ bool NativeInputManager::dispatchUnhandledKey(const sp<InputChannel>& inputChann if (policyFlags & POLICY_FLAG_TRUSTED) { JNIEnv* env = jniEnv(); - // Note: inputChannel may be null. - jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel); + // Note: inputWindowHandle may be null. + jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle); jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); if (keyEventObj) { jobject fallbackKeyEventObj = env->CallObjectMethod(mCallbacksObj, gCallbacksClassInfo.dispatchUnhandledKey, - inputChannelObj, keyEventObj, policyFlags); + inputWindowHandleObj, keyEventObj, policyFlags); checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey"); android_view_KeyEvent_recycle(env, keyEventObj); env->DeleteLocalRef(keyEventObj); @@ -935,7 +697,7 @@ bool NativeInputManager::dispatchUnhandledKey(const sp<InputChannel>& inputChann } else { LOGE("Failed to obtain key event object for dispatchUnhandledKey."); } - env->DeleteLocalRef(inputChannelObj); + env->DeleteLocalRef(inputWindowHandleObj); } return result; } @@ -1079,7 +841,7 @@ static void android_server_InputManager_handleInputChannelDisposed(JNIEnv* env, } static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, jclass clazz, - jobject inputChannelObj, jboolean monitor) { + jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) { if (checkInputManagerUnitialized(env)) { return; } @@ -1091,9 +853,11 @@ static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, return; } + sp<InputWindowHandle> inputWindowHandle = + android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj); status_t status = gNativeInputManager->registerInputChannel( - env, inputChannel, inputChannelObj, monitor); + env, inputChannel, inputWindowHandle, monitor); if (status) { jniThrowRuntimeException(env, "Failed to register input channel. " "Check logs for details."); @@ -1311,7 +1075,8 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) android_server_InputManager_nativeGetSwitchState }, { "nativeHasKeys", "(II[I[Z)Z", (void*) android_server_InputManager_nativeHasKeys }, - { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;Z)V", + { "nativeRegisterInputChannel", + "(Landroid/view/InputChannel;Lcom/android/server/InputWindowHandle;Z)V", (void*) android_server_InputManager_nativeRegisterInputChannel }, { "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V", (void*) android_server_InputManager_nativeUnregisterInputChannel }, @@ -1364,21 +1129,22 @@ int register_android_server_InputManager(JNIEnv* env) { "notifyLidSwitchChanged", "(JZ)V"); GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, gCallbacksClassInfo.clazz, - "notifyInputChannelBroken", "(Landroid/view/InputChannel;)V"); + "notifyInputChannelBroken", "(Lcom/android/server/InputWindowHandle;)V"); GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz, - "notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J"); + "notifyANR", + "(Lcom/android/server/InputApplicationHandle;Lcom/android/server/InputWindowHandle;)J"); GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz, "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I"); GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz, "interceptKeyBeforeDispatching", - "(Landroid/view/InputChannel;Landroid/view/KeyEvent;I)Z"); + "(Lcom/android/server/InputWindowHandle;Landroid/view/KeyEvent;I)Z"); GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, gCallbacksClassInfo.clazz, "dispatchUnhandledKey", - "(Landroid/view/InputChannel;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;"); + "(Lcom/android/server/InputWindowHandle;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;"); GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz, "checkInjectEventsPermission", "(II)Z"); @@ -1401,99 +1167,6 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gCallbacksClassInfo.getPointerIcon, gCallbacksClassInfo.clazz, "getPointerIcon", "()Lcom/android/server/InputManager$PointerIcon;"); - // InputWindow - - FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow"); - - GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz, - "inputChannel", "Landroid/view/InputChannel;"); - - GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz, - "name", "Ljava/lang/String;"); - - GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz, - "layoutParamsFlags", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, gInputWindowClassInfo.clazz, - "layoutParamsType", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, gInputWindowClassInfo.clazz, - "dispatchingTimeoutNanos", "J"); - - GET_FIELD_ID(gInputWindowClassInfo.frameLeft, gInputWindowClassInfo.clazz, - "frameLeft", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz, - "frameTop", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz, - "frameRight", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz, - "frameBottom", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz, - "visibleFrameLeft", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz, - "visibleFrameTop", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz, - "visibleFrameRight", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz, - "visibleFrameBottom", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz, - "touchableAreaLeft", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz, - "touchableAreaTop", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz, - "touchableAreaRight", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz, - "touchableAreaBottom", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz, - "visible", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz, - "canReceiveKeys", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz, - "hasFocus", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, gInputWindowClassInfo.clazz, - "hasWallpaper", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz, - "paused", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz, - "layer", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz, - "ownerPid", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.ownerUid, gInputWindowClassInfo.clazz, - "ownerUid", "I"); - - // InputApplication - - FIND_CLASS(gInputApplicationClassInfo.clazz, "com/android/server/InputApplication"); - - GET_FIELD_ID(gInputApplicationClassInfo.name, gInputApplicationClassInfo.clazz, - "name", "Ljava/lang/String;"); - - GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos, - gInputApplicationClassInfo.clazz, - "dispatchingTimeoutNanos", "J"); - - GET_FIELD_ID(gInputApplicationClassInfo.token, gInputApplicationClassInfo.clazz, - "token", "Ljava/lang/Object;"); - // KeyEvent FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent"); diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp new file mode 100644 index 000000000000..a4609a0f9b85 --- /dev/null +++ b/services/jni/com_android_server_InputWindow.cpp @@ -0,0 +1,240 @@ +/* + * 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 "InputWindow" + +#include "JNIHelp.h" +#include "jni.h" +#include <android_runtime/AndroidRuntime.h> + +#include <android_view_InputChannel.h> +#include "com_android_server_InputWindow.h" +#include "com_android_server_InputWindowHandle.h" + +namespace android { + +static struct { + jclass clazz; + + jfieldID inputWindowHandle; + jfieldID inputChannel; + jfieldID name; + jfieldID layoutParamsFlags; + jfieldID layoutParamsType; + jfieldID dispatchingTimeoutNanos; + jfieldID frameLeft; + jfieldID frameTop; + jfieldID frameRight; + jfieldID frameBottom; + jfieldID visibleFrameLeft; + jfieldID visibleFrameTop; + jfieldID visibleFrameRight; + jfieldID visibleFrameBottom; + jfieldID touchableAreaLeft; + jfieldID touchableAreaTop; + jfieldID touchableAreaRight; + jfieldID touchableAreaBottom; + jfieldID visible; + jfieldID canReceiveKeys; + jfieldID hasFocus; + jfieldID hasWallpaper; + jfieldID paused; + jfieldID layer; + jfieldID ownerPid; + jfieldID ownerUid; +} gInputWindowClassInfo; + + +// --- Global functions --- + +void android_server_InputWindow_toNative( + JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow) { + jobject inputWindowHandleObj = env->GetObjectField(inputWindowObj, + gInputWindowClassInfo.inputWindowHandle); + if (inputWindowHandleObj) { + outInputWindow->inputWindowHandle = + android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj); + env->DeleteLocalRef(inputWindowHandleObj); + } else { + outInputWindow->inputWindowHandle = NULL; + } + + jobject inputChannelObj = env->GetObjectField(inputWindowObj, + gInputWindowClassInfo.inputChannel); + if (inputChannelObj) { + outInputWindow->inputChannel = + android_view_InputChannel_getInputChannel(env, inputChannelObj); + env->DeleteLocalRef(inputChannelObj); + } else { + outInputWindow->inputChannel = NULL; + } + + jstring nameObj = jstring(env->GetObjectField(inputWindowObj, + gInputWindowClassInfo.name)); + if (nameObj) { + const char* nameStr = env->GetStringUTFChars(nameObj, NULL); + outInputWindow->name.setTo(nameStr); + env->ReleaseStringUTFChars(nameObj, nameStr); + env->DeleteLocalRef(nameObj); + } else { + LOGE("InputWindow.name should not be null."); + outInputWindow->name.setTo("unknown"); + } + + outInputWindow->layoutParamsFlags = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.layoutParamsFlags); + outInputWindow->layoutParamsType = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.layoutParamsType); + outInputWindow->dispatchingTimeout = env->GetLongField(inputWindowObj, + gInputWindowClassInfo.dispatchingTimeoutNanos); + outInputWindow->frameLeft = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.frameLeft); + outInputWindow->frameTop = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.frameTop); + outInputWindow->frameRight = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.frameRight); + outInputWindow->frameBottom = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.frameBottom); + outInputWindow->visibleFrameLeft = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.visibleFrameLeft); + outInputWindow->visibleFrameTop = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.visibleFrameTop); + outInputWindow->visibleFrameRight = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.visibleFrameRight); + outInputWindow->visibleFrameBottom = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.visibleFrameBottom); + outInputWindow->touchableAreaLeft = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.touchableAreaLeft); + outInputWindow->touchableAreaTop = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.touchableAreaTop); + outInputWindow->touchableAreaRight = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.touchableAreaRight); + outInputWindow->touchableAreaBottom = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.touchableAreaBottom); + outInputWindow->visible = env->GetBooleanField(inputWindowObj, + gInputWindowClassInfo.visible); + outInputWindow->canReceiveKeys = env->GetBooleanField(inputWindowObj, + gInputWindowClassInfo.canReceiveKeys); + outInputWindow->hasFocus = env->GetBooleanField(inputWindowObj, + gInputWindowClassInfo.hasFocus); + outInputWindow->hasWallpaper = env->GetBooleanField(inputWindowObj, + gInputWindowClassInfo.hasWallpaper); + outInputWindow->paused = env->GetBooleanField(inputWindowObj, + gInputWindowClassInfo.paused); + outInputWindow->layer = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.layer); + outInputWindow->ownerPid = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.ownerPid); + outInputWindow->ownerUid = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.ownerUid); +} + + +// --- JNI --- + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + +int register_android_server_InputWindow(JNIEnv* env) { + FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow"); + + GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, gInputWindowClassInfo.clazz, + "inputWindowHandle", "Lcom/android/server/InputWindowHandle;"); + + GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz, + "inputChannel", "Landroid/view/InputChannel;"); + + GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz, + "name", "Ljava/lang/String;"); + + GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz, + "layoutParamsFlags", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, gInputWindowClassInfo.clazz, + "layoutParamsType", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, gInputWindowClassInfo.clazz, + "dispatchingTimeoutNanos", "J"); + + GET_FIELD_ID(gInputWindowClassInfo.frameLeft, gInputWindowClassInfo.clazz, + "frameLeft", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz, + "frameTop", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz, + "frameRight", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz, + "frameBottom", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz, + "visibleFrameLeft", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz, + "visibleFrameTop", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz, + "visibleFrameRight", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz, + "visibleFrameBottom", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz, + "touchableAreaLeft", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz, + "touchableAreaTop", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz, + "touchableAreaRight", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz, + "touchableAreaBottom", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz, + "visible", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz, + "canReceiveKeys", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz, + "hasFocus", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, gInputWindowClassInfo.clazz, + "hasWallpaper", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz, + "paused", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz, + "layer", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz, + "ownerPid", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.ownerUid, gInputWindowClassInfo.clazz, + "ownerUid", "I"); + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_InputWindow.h b/services/jni/com_android_server_InputWindow.h new file mode 100644 index 000000000000..eaf7bdedbd7c --- /dev/null +++ b/services/jni/com_android_server_InputWindow.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef _ANDROID_SERVER_INPUT_WINDOW_H +#define _ANDROID_SERVER_INPUT_WINDOW_H + +#include <input/InputWindow.h> + +#include "JNIHelp.h" +#include "jni.h" + +namespace android { + +extern void android_server_InputWindow_toNative( + JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow); + +} // namespace android + +#endif // _ANDROID_SERVER_INPUT_WINDOW_H diff --git a/services/jni/com_android_server_InputWindowHandle.cpp b/services/jni/com_android_server_InputWindowHandle.cpp new file mode 100644 index 000000000000..4d66212087ca --- /dev/null +++ b/services/jni/com_android_server_InputWindowHandle.cpp @@ -0,0 +1,135 @@ +/* + * 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 "InputWindowHandle" + +#include "JNIHelp.h" +#include "jni.h" +#include <android_runtime/AndroidRuntime.h> +#include <utils/threads.h> + +#include "com_android_server_InputWindowHandle.h" +#include "com_android_server_InputApplicationHandle.h" + +namespace android { + +static struct { + jclass clazz; + + jfieldID ptr; + jfieldID inputApplicationHandle; +} gInputWindowHandleClassInfo; + +static Mutex gHandleMutex; + + +// --- NativeInputWindowHandle --- + +NativeInputWindowHandle::NativeInputWindowHandle( + const sp<InputApplicationHandle>& inputApplicationHandle, jweak objWeak) : + InputWindowHandle(inputApplicationHandle), + mObjWeak(objWeak) { +} + +NativeInputWindowHandle::~NativeInputWindowHandle() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->DeleteWeakGlobalRef(mObjWeak); +} + +jobject NativeInputWindowHandle::getInputWindowHandleObjLocalRef(JNIEnv* env) { + return env->NewLocalRef(mObjWeak); +} + + +// --- Global functions --- + +sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle( + JNIEnv* env, jobject inputWindowHandleObj) { + if (!inputWindowHandleObj) { + return NULL; + } + + AutoMutex _l(gHandleMutex); + + int ptr = env->GetIntField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr); + NativeInputWindowHandle* handle; + if (ptr) { + handle = reinterpret_cast<NativeInputWindowHandle*>(ptr); + } else { + jobject inputApplicationHandleObj = env->GetObjectField(inputWindowHandleObj, + gInputWindowHandleClassInfo.inputApplicationHandle); + sp<InputApplicationHandle> inputApplicationHandle = + android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj); + env->DeleteLocalRef(inputApplicationHandleObj); + + jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj); + handle = new NativeInputWindowHandle(inputApplicationHandle, objWeak); + handle->incStrong(inputWindowHandleObj); + env->SetIntField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr, + reinterpret_cast<int>(handle)); + } + return handle; +} + + +// --- JNI --- + +static void android_server_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) { + AutoMutex _l(gHandleMutex); + + int ptr = env->GetIntField(obj, gInputWindowHandleClassInfo.ptr); + if (ptr) { + env->SetIntField(obj, gInputWindowHandleClassInfo.ptr, 0); + + NativeInputWindowHandle* handle = reinterpret_cast<NativeInputWindowHandle*>(ptr); + handle->decStrong(obj); + } +} + + +static JNINativeMethod gInputWindowHandleMethods[] = { + /* name, signature, funcPtr */ + { "nativeDispose", "()V", + (void*) android_server_InputWindowHandle_nativeDispose }, +}; + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + +int register_android_server_InputWindowHandle(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "com/android/server/InputWindowHandle", + gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + FIND_CLASS(gInputWindowHandleClassInfo.clazz, "com/android/server/InputWindowHandle"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, gInputWindowHandleClassInfo.clazz, + "ptr", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle, + gInputWindowHandleClassInfo.clazz, + "inputApplicationHandle", "Lcom/android/server/InputApplicationHandle;"); + + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_InputWindowHandle.h b/services/jni/com_android_server_InputWindowHandle.h new file mode 100644 index 000000000000..43f2a6ba9536 --- /dev/null +++ b/services/jni/com_android_server_InputWindowHandle.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#ifndef _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H +#define _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H + +#include <input/InputWindow.h> + +#include "JNIHelp.h" +#include "jni.h" + +namespace android { + +class NativeInputWindowHandle : public InputWindowHandle { +public: + NativeInputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle, + jweak objWeak); + virtual ~NativeInputWindowHandle(); + + jobject getInputWindowHandleObjLocalRef(JNIEnv* env); + +private: + jweak mObjWeak; +}; + + +extern sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle( + JNIEnv* env, jobject inputWindowHandleObj); + +} // namespace android + +#endif // _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index cd4f0a46c517..bdd6d808ac42 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -6,6 +6,10 @@ namespace android { int register_android_server_AlarmManagerService(JNIEnv* env); int register_android_server_BatteryService(JNIEnv* env); +int register_android_server_InputApplication(JNIEnv* env); +int register_android_server_InputApplicationHandle(JNIEnv* env); +int register_android_server_InputWindow(JNIEnv* env); +int register_android_server_InputWindowHandle(JNIEnv* env); int register_android_server_InputManager(JNIEnv* env); int register_android_server_LightsService(JNIEnv* env); int register_android_server_PowerManagerService(JNIEnv* env); @@ -28,6 +32,10 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) LOG_ASSERT(env, "Could not retrieve the env!"); register_android_server_PowerManagerService(env); + register_android_server_InputApplication(env); + register_android_server_InputApplicationHandle(env); + register_android_server_InputWindow(env); + register_android_server_InputWindowHandle(env); register_android_server_InputManager(env); register_android_server_LightsService(env); register_android_server_AlarmManagerService(env); diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java index 91e3b84613c4..8ca842e397c0 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java @@ -23,6 +23,7 @@ import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.view.View; @@ -31,7 +32,9 @@ public class LinesActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + getWindow().setBackgroundDrawable(new ColorDrawable(0xffffffff)); final LinesView view = new LinesView(this); + //view.setAlpha(0.80f); setContentView(view); } @@ -91,8 +94,6 @@ public class LinesActivity extends Activity { protected void onDraw(Canvas canvas) { super.onDraw(canvas); - canvas.drawARGB(255, 255, 255, 255); - canvas.save(); canvas.translate(100.0f, 20.0f); diff --git a/tests/StatusBar/AndroidManifest.xml b/tests/StatusBar/AndroidManifest.xml index ddb756b42539..81442bfc60a4 100644 --- a/tests/StatusBar/AndroidManifest.xml +++ b/tests/StatusBar/AndroidManifest.xml @@ -5,6 +5,7 @@ <uses-permission android:name="android.permission.STATUS_BAR" /> <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" /> <uses-permission android:name="android.permission.VIBRATE" /> + <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" /> <application> <activity android:name="StatusBarTest" android:label="_StatusBar"> diff --git a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java index 92d5bee00b06..31a1cf5ada32 100644 --- a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java +++ b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java @@ -26,6 +26,8 @@ import android.os.IBinder; import android.os.IPowerManager; import android.widget.ListView; import android.content.Intent; +import android.content.ComponentName; +import android.content.pm.PackageManager; import android.app.Notification; import android.app.NotificationManager; import android.app.StatusBarManager; @@ -66,6 +68,24 @@ public class PowerTest extends TestActivity return mTests; } private Test[] mTests = new Test[] { + new Test("Enable settings widget") { + public void run() { + PackageManager pm = getPackageManager(); + pm.setComponentEnabledSetting(new ComponentName("com.android.settings", + "com.android.settings.widget.SettingsAppWidgetProvider"), + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); + + } + }, + new Test("Disable settings widget") { + public void run() { + PackageManager pm = getPackageManager(); + pm.setComponentEnabledSetting(new ComponentName("com.android.settings", + "com.android.settings.widget.SettingsAppWidgetProvider"), + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0); + + } + }, new Test("Enable proximity") { public void run() { mProx.acquire(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java index 886ef2ac5729..4fb280d585cd 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java @@ -328,11 +328,12 @@ public final class BridgeTypedArray extends TypedArray { } // looks like were unable to resolve the color value. - assert false; Bridge.getLog().warning(null, String.format( "Unable to resolve color value \"%1$s\" in attribute \"%2$s\"", value, mNames[index])); + assert false; + return null; } @@ -406,11 +407,12 @@ public final class BridgeTypedArray extends TypedArray { } // looks like we were unable to resolve the dimension value - assert false; Bridge.getLog().warning(null, String.format( "Unable to resolve dimension value \"%1$s\" in attribute \"%2$s\"", s, mNames[index])); + assert false; + return defValue; } @@ -536,11 +538,12 @@ public final class BridgeTypedArray extends TypedArray { } // looks like we were unable to resolve the fraction value - assert false; Bridge.getLog().warning(null, String.format( "Unable to resolve fraction value \"%1$s\" in attribute \"%2$s\"", value, mNames[index])); + assert false; + return defValue; } @@ -644,9 +647,11 @@ public final class BridgeTypedArray extends TypedArray { return idValue.intValue(); } - assert false; Bridge.getLog().warning(null, String.format( "Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index])); + + assert false; + return defValue; } @@ -679,11 +684,12 @@ public final class BridgeTypedArray extends TypedArray { } // looks like we were unable to resolve the drawable - assert false; Bridge.getLog().warning(null, String.format( "Unable to resolve drawable \"%1$s\" in attribute \"%2$s\"", stringValue, mNames[index])); + assert false; + return null; } |