diff options
51 files changed, 1238 insertions, 947 deletions
diff --git a/api/current.xml b/api/current.xml index 375448c..1fe1498 100644 --- a/api/current.xml +++ b/api/current.xml @@ -134225,6 +134225,17 @@ visibility="public" > </constructor> +<field name="BATTERY_HEALTH_COLD" + type="int" + transient="false" + volatile="false" + value="7" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="BATTERY_HEALTH_DEAD" type="int" transient="false" @@ -225133,6 +225144,19 @@ <parameter name="filterText" type="java.lang.String"> </parameter> </method> +<method name="setFriction" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="friction" type="float"> +</parameter> +</method> <method name="setItemChecked" return="void" abstract="false" @@ -238694,6 +238718,19 @@ <parameter name="newY" type="int"> </parameter> </method> +<method name="setFriction" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="friction" type="float"> +</parameter> +</method> <method name="startScroll" return="void" abstract="false" diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 2a5181f..b9a541d 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -28,6 +28,7 @@ import android.os.Environment; import android.os.ParcelFileDescriptor; import android.provider.BaseColumns; import android.provider.Downloads; +import android.util.Log; import android.util.Pair; import java.io.File; @@ -53,6 +54,8 @@ import java.util.Set; * download in a notification or from the downloads UI. */ public class DownloadManager { + private static final String TAG = "DownloadManager"; + /** * An identifier for a particular download, unique across the system. Clients use this ID to * make subsequent calls related to the download. @@ -754,20 +757,11 @@ public class DownloadManager { * @return the number of downloads actually removed */ public int remove(long... ids) { - StringBuilder whereClause = new StringBuilder(); - String[] whereArgs = new String[ids.length]; - - whereClause.append(Downloads.Impl._ID + " IN ("); - for (int i = 0; i < ids.length; i++) { - if (i > 0) { - whereClause.append(","); - } - whereClause.append("?"); - whereArgs[i] = Long.toString(ids[i]); + if (ids == null || ids.length == 0) { + // called with nothing to remove! + throw new IllegalArgumentException("input param 'ids' can't be null"); } - whereClause.append(")"); - - return mResolver.delete(mBaseUri, whereClause.toString(), whereArgs); + return mResolver.delete(mBaseUri, getWhereClauseForIds(ids), getWhereArgsForIds(ids)); } /** @@ -834,12 +828,13 @@ public class DownloadManager { */ static String getWhereClauseForIds(long[] ids) { StringBuilder whereClause = new StringBuilder(); - whereClause.append(Downloads.Impl._ID + " IN ("); + whereClause.append("("); for (int i = 0; i < ids.length; i++) { if (i > 0) { - whereClause.append(","); + whereClause.append("OR "); } - whereClause.append("?"); + whereClause.append(Downloads.Impl._ID); + whereClause.append(" = ? "); } whereClause.append(")"); return whereClause.toString(); diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java index c0788f5..4d9ee54 100644 --- a/core/java/android/content/SharedPreferences.java +++ b/core/java/android/content/SharedPreferences.java @@ -198,9 +198,21 @@ public interface SharedPreferences { * {@link #commit} will block until all async commits are * completed as well as the commit itself. * - * <p>If you call this from an {@link android.app.Activity}, - * the base class will wait for any async commits to finish in - * its {@link android.app.Activity#onPause}.</p> + * <p>As {@link SharedPreferences} instances are singletons within + * a process, it's safe to replace any instance of {@link #commit} with + * {@link #apply} if you were already ignoring the return value. + * + * <p>You don't need to worry about Android component + * lifecycles and their interaction with <code>apply()</code> + * writing to disk. The framework makes sure in-flight disk + * writes from <code>apply()</code> complete before switching + * states. + * + * <p class='note'>The SharedPreferences.Editor interface + * isn't expected to be implemented directly. However, if you + * previously did implement it and are now getting errors + * about missing <code>apply()</code>, you can simply call + * {@link #commit} from <code>apply()</code>. */ void apply(); } diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index 5fd2246..247b281 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -107,6 +107,7 @@ public class BatteryManager { public static final int BATTERY_HEALTH_DEAD = 4; public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5; public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6; + public static final int BATTERY_HEALTH_COLD = 7; // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent. // These must be powers of 2. diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index 17b2e82..12b9f0c 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -1242,7 +1242,14 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis private void tryCommit(SharedPreferences.Editor editor) { if (mPreferenceManager.shouldCommit()) { - editor.apply(); + try { + editor.apply(); + } catch (AbstractMethodError unused) { + // The app injected its own pre-Gingerbread + // SharedPreferences.Editor implementation without + // an apply method. + editor.commit(); + } } } diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java index 42150ed..6562de9 100644 --- a/core/java/android/preference/PreferenceManager.java +++ b/core/java/android/preference/PreferenceManager.java @@ -461,7 +461,16 @@ public class PreferenceManager { pm.setSharedPreferencesMode(sharedPreferencesMode); pm.inflateFromResource(context, resId, null); - defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true).apply(); + SharedPreferences.Editor editor = + defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true); + try { + editor.apply(); + } catch (AbstractMethodError unused) { + // The app injected its own pre-Gingerbread + // SharedPreferences.Editor implementation without + // an apply method. + editor.commit(); + } } } @@ -496,15 +505,21 @@ public class PreferenceManager { boolean shouldCommit() { return !mNoCommit; } - + private void setNoCommit(boolean noCommit) { if (!noCommit && mEditor != null) { - mEditor.apply(); + try { + mEditor.apply(); + } catch (AbstractMethodError unused) { + // The app injected its own pre-Gingerbread + // SharedPreferences.Editor implementation without + // an apply method. + mEditor.commit(); + } } - mNoCommit = noCommit; } - + /** * Returns the activity that shows the preferences. This is useful for doing * managed queries, but in most cases the use of {@link #getContext()} is diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 912180b..0e5ece1 100755 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -46,10 +46,12 @@ import android.view.KeyCharacterMap.KeyData; * with the special action {@link #ACTION_MULTIPLE} that either specifies * that single repeated key code or a sequence of characters to insert. * </p><p> - * In general, the framework makes no guarantees that the key events delivered - * to a view constitute a complete key press. In particular, there is no - * guarantee that a view will always receive a key event with {@link #ACTION_UP} - * for each {@link #ACTION_DOWN} that was delivered. + * In general, the framework cannot guarantee that the key events it delivers + * to a view always constitute complete key sequences since some events may be dropped + * or modified by containing views before they are delivered. The view implementation + * should be prepared to handle {@link #FLAG_CANCELED} and should tolerate anomalous + * situations such as receiving a new {@link #ACTION_DOWN} without first having + * received an {@link #ACTION_UP} for the prior key press. * </p><p> * Refer to {@link InputDevice} for more information about how different kinds of * input devices and sources represent keys and buttons. diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index dfbe65c..9411474 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -82,10 +82,12 @@ import android.os.SystemClock; * } * } * </code></pre></p><p> - * In general, the framework makes no guarantees that the motion events delivered - * to a view constitute a complete gesture. In particular, there is no - * guarantee that a view will always receive a motion event with {@link #ACTION_UP} - * for each {@link #ACTION_DOWN} that was delivered. + * In general, the framework cannot guarantee that the motion events it delivers + * to a view always constitute a complete motion sequences since some events may be dropped + * or modified by containing views before they are delivered. The view implementation + * should be prepared to handle {@link #ACTION_CANCEL} and should tolerate anomalous + * situations such as receiving a new {@link #ACTION_DOWN} without first having + * received an {@link #ACTION_UP} for the prior gesture. * </p><p> * Refer to {@link InputDevice} for more information about how different kinds of * input devices and sources represent pointer coordinates. diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index acdfc28..f413475 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -25,6 +25,20 @@ import android.util.SparseArray; */ public class ViewConfiguration { /** + * Expected bit depth of the display panel. + * + * @hide + */ + public static final float PANEL_BIT_DEPTH = 24; + + /** + * Minimum alpha required for a view to draw. + * + * @hide + */ + public static final float ALPHA_THRESHOLD = 0.5f / PANEL_BIT_DEPTH; + + /** * Defines the width of the horizontal scrollbar and the height of the vertical scrollbar in * pixels */ diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 5b3a091..be6aa43 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -69,7 +69,7 @@ import java.util.ArrayList; public abstract class ViewGroup extends View implements ViewParent, ViewManager { private static final boolean DBG = false; - + /** * Views which have been hidden or removed which need to be animated on * their way out. @@ -2185,6 +2185,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager (child.mPrivateFlags & DRAW_ANIMATION) == 0) { return more; } + + float alpha = child.getAlpha(); + // Bail out early if the view does not need to be drawn + if (alpha <= ViewConfiguration.ALPHA_THRESHOLD) return more; child.computeScroll(); @@ -2217,8 +2221,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } - float alpha = child.getAlpha(); - if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) { int transX = 0; int transY = 0; @@ -2253,7 +2255,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (alpha < 1.0f) { mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; - + if (hasNoCache) { final int multipliedAlpha = (int) (255 * alpha); if (!child.onSetAlpha(multipliedAlpha)) { diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 954b3e7..1fd31a3 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -65,6 +65,7 @@ import android.view.animation.Animation; * @hide */ public interface WindowManagerPolicy { + // Policy flags. These flags are also defined in frameworks/base/include/ui/Input.h. public final static int FLAG_WAKE = 0x00000001; public final static int FLAG_WAKE_DROPPED = 0x00000002; public final static int FLAG_SHIFT = 0x00000004; @@ -76,9 +77,11 @@ public interface WindowManagerPolicy { public final static int FLAG_VIRTUAL = 0x00000100; public final static int FLAG_INJECTED = 0x01000000; + public final static int FLAG_TRUSTED = 0x02000000; public final static int FLAG_WOKE_HERE = 0x10000000; public final static int FLAG_BRIGHT_HERE = 0x20000000; + public final static int FLAG_PASS_TO_USER = 0x40000000; public final static boolean WATCH_POINTER = false; diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 5d68613..8c1e5f7 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -317,6 +317,10 @@ public class WebView extends AbsoluteLayout // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK private boolean mAutoRedraw; + // Reference to the AlertDialog displayed by InvokeListBox. + // It's used to dismiss the dialog in destroy if not done before. + private AlertDialog mListBoxDialog = null; + static final String LOGTAG = "webview"; private ZoomManager mZoomManager; @@ -1301,7 +1305,10 @@ public class WebView extends AbsoluteLayout */ public void destroy() { clearHelpers(); - + if (mListBoxDialog != null) { + mListBoxDialog.dismiss(); + mListBoxDialog = null; + } if (mWebViewCore != null) { // Set the handlers to null before destroying WebViewCore so no // more messages will be posted. @@ -7263,7 +7270,7 @@ public class WebView extends AbsoluteLayout EventHub.SINGLE_LISTBOX_CHOICE, -2, 0); }}); } - final AlertDialog dialog = b.create(); + mListBoxDialog = b.create(); listView.setAdapter(adapter); listView.setFocusableInTouchMode(true); // There is a bug (1250103) where the checks in a ListView with @@ -7285,7 +7292,8 @@ public class WebView extends AbsoluteLayout int position, long id) { mWebViewCore.sendMessage( EventHub.SINGLE_LISTBOX_CHOICE, (int)id, 0); - dialog.dismiss(); + mListBoxDialog.dismiss(); + mListBoxDialog = null; } }); if (mSelection != -1) { @@ -7297,13 +7305,14 @@ public class WebView extends AbsoluteLayout adapter.registerDataSetObserver(observer); } } - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + mListBoxDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { mWebViewCore.sendMessage( EventHub.SINGLE_LISTBOX_CHOICE, -2, 0); + mListBoxDialog = null; } }); - dialog.show(); + mListBoxDialog.show(); } } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index c694ff1..2af59f9 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2965,7 +2965,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int firstPos = mFirstPosition; final int lastPos = firstPos + getChildCount() - 1; - int viewTravelCount = 0; + int viewTravelCount; if (position <= firstPos) { viewTravelCount = firstPos - position + 1; mMode = MOVE_UP_POS; @@ -2998,7 +2998,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int firstPos = mFirstPosition; final int lastPos = firstPos + getChildCount() - 1; - int viewTravelCount = 0; + int viewTravelCount; if (position <= firstPos) { final int boundPosFromLast = lastPos - boundPosition; if (boundPosFromLast < 1) { @@ -3059,7 +3059,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int childCount = getChildCount(); final int lastPos = firstPos + childCount - 1; - int viewTravelCount = 0; + int viewTravelCount; if (position < firstPos) { viewTravelCount = firstPos - position; } else if (position > lastPos) { @@ -3249,6 +3249,20 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } /** + * The amount of friction applied to flings. The default value + * is {@link ViewConfiguration#getScrollFriction}. + * + * @return A scalar dimensionless value representing the coefficient of + * friction. + */ + public void setFriction(float friction) { + if (mFlingRunnable == null) { + mFlingRunnable = new FlingRunnable(); + } + mFlingRunnable.mScroller.setFriction(friction); + } + + /** * Smoothly scroll to the specified adapter position. The view will * scroll such that the indicated position is displayed. * @param position Scroll to this adapter position. @@ -3581,22 +3595,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @return The position of the first (or only) item in the row containing y */ abstract int findMotionRow(int y); - - /** - * Find the row closest to y. This row will be used as the motion row when scrolling. - * - * @param y Where the user touched - * @return The position of the first (or only) item in the row closest to y - */ - int findClosestMotionRow(int y) { - final int childCount = getChildCount(); - if (childCount == 0) { - return INVALID_POSITION; - } - - final int motionRow = findMotionRow(y); - return motionRow != INVALID_POSITION ? motionRow : mFirstPosition + childCount - 1; - } /** * Causes all the views to be rebuilt and redrawn. diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index aa14c81..d3aa42f 100755 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -17,14 +17,14 @@ package android.widget; import com.android.internal.R; + import android.content.Context; -import android.content.res.Resources; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageParser; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; -import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; import android.util.Log; import android.view.LayoutInflater; @@ -329,11 +329,6 @@ public class AppSecurityPermissions implements View.OnClickListener { TextView permGrpView = (TextView) permView.findViewById(R.id.permission_group); TextView permDescView = (TextView) permView.findViewById(R.id.permission_list); - if (dangerous) { - final Resources resources = context.getResources(); - permGrpView.setTextColor(resources.getColor(R.color.perms_dangerous_grp_color)); - permDescView.setTextColor(resources.getColor(R.color.perms_dangerous_perm_color)); - } ImageView imgView = (ImageView)permView.findViewById(R.id.perm_icon); imgView.setImageDrawable(icon); diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 7c4897a..b5e103f 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -26,7 +26,6 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.SparseBooleanArray; @@ -2980,7 +2979,6 @@ public class ListView extends AbsListView { if (!mStackFromBottom) { int bottom; - final int scrollY = mScrollY; for (int i = 0; i < count; i++) { if ((headerDividers || first + i >= headerCount) && (footerDividers || first + i < footerLimit)) { diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java index 4cb0839..d2e6688 100644 --- a/core/java/android/widget/Scroller.java +++ b/core/java/android/widget/Scroller.java @@ -63,7 +63,8 @@ public class Scroller { private static final int SCROLL_MODE = 0; private static final int FLING_MODE = 1; - private final float mDeceleration; + private float mDeceleration; + private final float mPpi; /** * Create a Scroller with the default duration and interpolator. @@ -79,13 +80,28 @@ public class Scroller { public Scroller(Context context, Interpolator interpolator) { mFinished = true; mInterpolator = interpolator; - float ppi = context.getResources().getDisplayMetrics().density * 160.0f; - mDeceleration = SensorManager.GRAVITY_EARTH // g (m/s^2) - * 39.37f // inch/meter - * ppi // pixels per inch - * ViewConfiguration.getScrollFriction(); + mPpi = context.getResources().getDisplayMetrics().density * 160.0f; + mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction()); + } + + /** + * The amount of friction applied to flings. The default value + * is {@link ViewConfiguration#getScrollFriction}. + * + * @return A scalar dimensionless value representing the coefficient of + * friction. + */ + public final void setFriction(float friction) { + computeDeceleration(friction); } + private float computeDeceleration(float friction) { + return SensorManager.GRAVITY_EARTH // g (m/s^2) + * 39.37f // inch/meter + * mPpi // pixels per inch + * friction; + } + /** * * Returns whether the scroller has finished scrolling. diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java index 8104ece..d6f5db1 100644 --- a/core/java/com/android/internal/app/ShutdownThread.java +++ b/core/java/com/android/internal/app/ShutdownThread.java @@ -69,7 +69,8 @@ public final class ShutdownThread extends Thread { private boolean mActionDone; private Context mContext; private PowerManager mPowerManager; - private PowerManager.WakeLock mWakeLock; + private PowerManager.WakeLock mCpuWakeLock; + private PowerManager.WakeLock mScreenWakeLock; private Handler mHandler; private ShutdownThread() { @@ -187,20 +188,36 @@ public final class ShutdownThread extends Thread { pd.show(); - // start the thread that initiates shutdown sInstance.mContext = context; sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - sInstance.mWakeLock = null; + + // make sure we never fall asleep again + sInstance.mCpuWakeLock = null; + try { + sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu"); + sInstance.mCpuWakeLock.setReferenceCounted(false); + sInstance.mCpuWakeLock.acquire(); + } catch (SecurityException e) { + Log.w(TAG, "No permission to acquire wake lock", e); + sInstance.mCpuWakeLock = null; + } + + // also make sure the screen stays on for better user experience + sInstance.mScreenWakeLock = null; if (sInstance.mPowerManager.isScreenOn()) { try { - sInstance.mWakeLock = sInstance.mPowerManager.newWakeLock( - PowerManager.FULL_WAKE_LOCK, "Shutdown"); - sInstance.mWakeLock.acquire(); + sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock( + PowerManager.FULL_WAKE_LOCK, TAG + "-screen"); + sInstance.mScreenWakeLock.setReferenceCounted(false); + sInstance.mScreenWakeLock.acquire(); } catch (SecurityException e) { Log.w(TAG, "No permission to acquire wake lock", e); - sInstance.mWakeLock = null; + sInstance.mScreenWakeLock = null; } } + + // start the thread that initiates shutdown sInstance.mHandler = new Handler() { }; sInstance.start(); diff --git a/core/java/com/android/internal/content/SyncStateContentProviderHelper.java b/core/java/com/android/internal/content/SyncStateContentProviderHelper.java deleted file mode 100644 index 274082c..0000000 --- a/core/java/com/android/internal/content/SyncStateContentProviderHelper.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.content; - -import com.android.internal.util.ArrayUtils; - -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.database.sqlite.SQLiteDatabase; -import android.accounts.Account; -import android.content.ContentValues; -import android.provider.SyncStateContract; - -/** - * Extends the schema of a ContentProvider to include the _sync_state table - * and implements query/insert/update/delete to access that table using the - * authority "syncstate". This can be used to store the sync state for a - * set of accounts. - * - * @hide - */ -public class SyncStateContentProviderHelper { - private static final String SELECT_BY_ACCOUNT = - SyncStateContract.Columns.ACCOUNT_NAME + "=? AND " - + SyncStateContract.Columns.ACCOUNT_TYPE + "=?"; - - private static final String SYNC_STATE_TABLE = "_sync_state"; - private static final String SYNC_STATE_META_TABLE = "_sync_state_metadata"; - private static final String SYNC_STATE_META_VERSION_COLUMN = "version"; - - private static long DB_VERSION = 1; - - private static final String[] ACCOUNT_PROJECTION = - new String[]{SyncStateContract.Columns.ACCOUNT_NAME, - SyncStateContract.Columns.ACCOUNT_TYPE}; - - public static final String PATH = "syncstate"; - - private static final String QUERY_COUNT_SYNC_STATE_ROWS = - "SELECT count(*)" - + " FROM " + SYNC_STATE_TABLE - + " WHERE " + SyncStateContract.Columns._ID + "=?"; - - public void createDatabase(SQLiteDatabase db) { - db.execSQL("DROP TABLE IF EXISTS " + SYNC_STATE_TABLE); - db.execSQL("CREATE TABLE " + SYNC_STATE_TABLE + " (" - + SyncStateContract.Columns._ID + " INTEGER PRIMARY KEY," - + SyncStateContract.Columns.ACCOUNT_NAME + " TEXT NOT NULL," - + SyncStateContract.Columns.ACCOUNT_TYPE + " TEXT NOT NULL," - + SyncStateContract.Columns.DATA + " TEXT," - + "UNIQUE(" + SyncStateContract.Columns.ACCOUNT_NAME + ", " - + SyncStateContract.Columns.ACCOUNT_TYPE + "));"); - - db.execSQL("DROP TABLE IF EXISTS " + SYNC_STATE_META_TABLE); - db.execSQL("CREATE TABLE " + SYNC_STATE_META_TABLE + " (" - + SYNC_STATE_META_VERSION_COLUMN + " INTEGER);"); - ContentValues values = new ContentValues(); - values.put(SYNC_STATE_META_VERSION_COLUMN, DB_VERSION); - db.insert(SYNC_STATE_META_TABLE, SYNC_STATE_META_VERSION_COLUMN, values); - } - - public void onDatabaseOpened(SQLiteDatabase db) { - long version = DatabaseUtils.longForQuery(db, - "SELECT " + SYNC_STATE_META_VERSION_COLUMN + " FROM " + SYNC_STATE_META_TABLE, - null); - if (version != DB_VERSION) { - createDatabase(db); - } - } - - public Cursor query(SQLiteDatabase db, String[] projection, - String selection, String[] selectionArgs, String sortOrder) { - return db.query(SYNC_STATE_TABLE, projection, selection, selectionArgs, - null, null, sortOrder); - } - - public long insert(SQLiteDatabase db, ContentValues values) { - return db.replace(SYNC_STATE_TABLE, SyncStateContract.Columns.ACCOUNT_NAME, values); - } - - public int delete(SQLiteDatabase db, String userWhere, String[] whereArgs) { - return db.delete(SYNC_STATE_TABLE, userWhere, whereArgs); - } - - public int update(SQLiteDatabase db, ContentValues values, - String selection, String[] selectionArgs) { - return db.update(SYNC_STATE_TABLE, values, selection, selectionArgs); - } - - public int update(SQLiteDatabase db, long rowId, Object data) { - if (DatabaseUtils.longForQuery(db, QUERY_COUNT_SYNC_STATE_ROWS, - new String[]{Long.toString(rowId)}) < 1) { - return 0; - } - db.execSQL("UPDATE " + SYNC_STATE_TABLE - + " SET " + SyncStateContract.Columns.DATA + "=?" - + " WHERE " + SyncStateContract.Columns._ID + "=" + rowId, - new Object[]{data}); - // assume a row was modified since we know it exists - return 1; - } - - public void onAccountsChanged(SQLiteDatabase db, Account[] accounts) { - Cursor c = db.query(SYNC_STATE_TABLE, ACCOUNT_PROJECTION, null, null, null, null, null); - try { - while (c.moveToNext()) { - final String accountName = c.getString(0); - final String accountType = c.getString(1); - Account account = new Account(accountName, accountType); - if (!ArrayUtils.contains(accounts, account)) { - db.delete(SYNC_STATE_TABLE, SELECT_BY_ACCOUNT, - new String[]{accountName, accountType}); - } - } - } finally { - c.close(); - } - } -}
\ No newline at end of file diff --git a/core/res/res/drawable-hdpi/ic_bullet_key_permission.png b/core/res/res/drawable-hdpi/ic_bullet_key_permission.png Binary files differindex 98d95dc..b6b840a 100644 --- a/core/res/res/drawable-hdpi/ic_bullet_key_permission.png +++ b/core/res/res/drawable-hdpi/ic_bullet_key_permission.png diff --git a/core/res/res/layout/app_perms_summary.xml b/core/res/res/layout/app_perms_summary.xml index 7160743..bdbbfcb 100755 --- a/core/res/res/layout/app_perms_summary.xml +++ b/core/res/res/layout/app_perms_summary.xml @@ -65,21 +65,23 @@ android:layout_marginLeft="16dip" android:duplicateParentState="true"> - <ImageView - android:id="@+id/show_more_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - <TextView android:id="@+id/show_more_text" android:textAppearance="?android:attr/textAppearanceMedium" android:duplicateParentState="true" - android:layout_alignTop="@id/show_more_icon" + android:layout_alignTop="@+id/show_more_icon" android:layout_gravity="center_vertical" - android:paddingLeft="6dip" - android:layout_width="match_parent" + android:paddingLeft="36dip" + android:layout_weight="1" + android:layout_width="wrap_content" android:layout_height="wrap_content" /> + <ImageView + android:id="@id/show_more_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="12dip" /> + </LinearLayout> <View diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java index 91824e6..dc421d8 100644 --- a/graphics/java/android/renderscript/Element.java +++ b/graphics/java/android/renderscript/Element.java @@ -47,7 +47,7 @@ public class Element extends BaseObj { UNSIGNED_8 (8, 1), UNSIGNED_16 (9, 2), UNSIGNED_32 (10, 4), - //UNSIGNED_64 (11, 8), + UNSIGNED_64 (11, 8), BOOLEAN(12, 1), @@ -142,6 +142,13 @@ public class Element extends BaseObj { return rs.mElement_I32; } + public static Element U64(RenderScript rs) { + if(rs.mElement_U64 == null) { + rs.mElement_U64 = createUser(rs, DataType.UNSIGNED_64); + } + return rs.mElement_U64; + } + public static Element I64(RenderScript rs) { if(rs.mElement_I64 == null) { rs.mElement_I64 = createUser(rs, DataType.SIGNED_64); diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index 2774fea..0f9ed87 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -514,6 +514,7 @@ public class RenderScript { Element mElement_I16; Element mElement_U32; Element mElement_I32; + Element mElement_U64; Element mElement_I64; Element mElement_F32; Element mElement_F64; diff --git a/include/ui/Input.h b/include/ui/Input.h index ee40b85..8c6018b 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -71,6 +71,8 @@ namespace android { /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. + * + * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java. */ enum { /* These flags originate in RawEvents and are generally set in the key map. @@ -93,6 +95,10 @@ enum { // Indicates that the input event was injected. POLICY_FLAG_INJECTED = 0x01000000, + // Indicates that the input event is from a trusted source such as a directly attached + // input device or an application with system-wide event injection permission. + POLICY_FLAG_TRUSTED = 0x02000000, + /* These flags are set by the input reader policy as it intercepts each event. */ // Indicates that the screen was off when the event was received and the event @@ -102,6 +108,11 @@ enum { // Indicates that the screen was dim when the event was received and the event // should brighten the device. POLICY_FLAG_BRIGHT_HERE = 0x20000000, + + // Indicates that the event should be dispatched to applications. + // The input event should still be sent to the InputDispatcher so that it can see all + // input events received include those that it will not deliver. + POLICY_FLAG_PASS_TO_USER = 0x40000000, }; /* diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h index 246df8f..63185d3 100644 --- a/include/ui/InputDispatcher.h +++ b/include/ui/InputDispatcher.h @@ -282,10 +282,35 @@ public: */ virtual int32_t getMaxEventsPerSecond() = 0; + /* Intercepts a key event immediately before queueing it. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing such as updating policy flags. + * + * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event + * should be dispatched to applications. + */ + virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId, + int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode, + uint32_t& policyFlags) = 0; + + /* Intercepts a generic touch, trackball or other event before queueing it. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing such as updating policy flags. + * + * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event + * should be dispatched to applications. + */ + virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; + /* Allows the policy a chance to intercept a key before dispatching. */ virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, const KeyEvent* keyEvent, uint32_t policyFlags) = 0; + /* Notifies the policy about switch events. + */ + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0; + /* Poke user activity for an event dispatched to a window. */ virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0; @@ -333,6 +358,8 @@ public: int32_t metaState, int32_t edgeFlags, uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) = 0; + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0; /* Injects an input event and optionally waits for sync. * The synchronization mode determines whether the method blocks while waiting for @@ -416,6 +443,8 @@ public: int32_t metaState, int32_t edgeFlags, uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime); + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) ; virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis); @@ -458,6 +487,7 @@ private: mutable int32_t refCount; int32_t type; nsecs_t eventTime; + uint32_t policyFlags; InjectionState* injectionState; bool dispatchInProgress; // initially false, set to true while dispatching @@ -471,7 +501,6 @@ private: struct KeyEntry : EventEntry { int32_t deviceId; int32_t source; - uint32_t policyFlags; int32_t action; int32_t flags; int32_t keyCode; @@ -500,7 +529,6 @@ private: struct MotionEntry : EventEntry { int32_t deviceId; int32_t source; - uint32_t policyFlags; int32_t action; int32_t flags; int32_t metaState; @@ -675,7 +703,8 @@ private: Pool<DispatchEntry> mDispatchEntryPool; Pool<CommandEntry> mCommandEntryPool; - void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime); + void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime, + uint32_t policyFlags); void releaseEventEntryInjectionState(EventEntry* entry); }; @@ -696,21 +725,19 @@ private: BROKEN }; + // Specifies the sources to cancel. + enum CancelationOptions { + CANCEL_ALL_EVENTS = 0, + CANCEL_POINTER_EVENTS = 1, + CANCEL_NON_POINTER_EVENTS = 2, + }; + InputState(); ~InputState(); // Returns true if there is no state to be canceled. bool isNeutral() const; - // Returns true if the input state believes it is out of sync. - bool isOutOfSync() const; - - // Sets the input state to be out of sync if it is not neutral. - void setOutOfSync(); - - // Resets the input state out of sync flag. - void resetOutOfSync(); - // Records tracking information for an event that has just been published. // Returns whether the event is consistent with the current input state. Consistency trackEvent(const EventEntry* entry); @@ -723,16 +750,17 @@ private: // Returns whether the event is consistent with the current input state. Consistency trackMotion(const MotionEntry* entry); - // Synthesizes cancelation events for the current state. - void synthesizeCancelationEvents(Allocator* allocator, - Vector<EventEntry*>& outEvents) const; + // Synthesizes cancelation events for the current state and resets the tracked state. + void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator, + Vector<EventEntry*>& outEvents, CancelationOptions options); // Clears the current state. void clear(); - private: - bool mIsOutOfSync; + // Copies pointer-related parts of the input state to another instance. + void copyPointerStateTo(InputState& other) const; + private: struct KeyMemento { int32_t deviceId; int32_t source; @@ -756,6 +784,8 @@ private: Vector<KeyMemento> mKeyMementos; Vector<MotionMemento> mMotionMementos; + + static bool shouldCancelEvent(int32_t eventSource, CancelationOptions options); }; /* Manages the dispatch state associated with a single input channel. */ @@ -805,6 +835,13 @@ private: status_t initialize(); }; + enum DropReason { + DROP_REASON_NOT_DROPPED = 0, + DROP_REASON_POLICY = 1, + DROP_REASON_APP_SWITCH = 2, + DROP_REASON_DISABLED = 3, + }; + sp<InputDispatcherPolicyInterface> mPolicy; Mutex mLock; @@ -824,12 +861,16 @@ private: // Enqueues an inbound event. Returns true if mLooper->wake() should be called. bool enqueueInboundEventLocked(EventEntry* entry); + // Cleans up input state when dropping an inbound event. + void dropInboundEventLocked(EventEntry* entry, DropReason dropReason); + // App switch latency optimization. + bool mAppSwitchSawKeyDown; nsecs_t mAppSwitchDueTime; - static bool isAppSwitchKey(int32_t keyCode); + static bool isAppSwitchKeyCode(int32_t keyCode); + bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry); bool isAppSwitchPendingLocked(); - bool detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry); void resetPendingAppSwitchLocked(bool handled); // All registered connections mapped by receive pipe file descriptor. @@ -851,7 +892,7 @@ private: // Event injection and synchronization. Condition mInjectionResultAvailableCondition; - EventEntry* createEntryFromInjectedInputEventLocked(const InputEvent* event); + bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult); Condition mInjectionSyncFinishedCondition; @@ -886,7 +927,6 @@ private: void drainInboundQueueLocked(); void releasePendingEventLocked(); void releaseInboundEventLocked(EventEntry* entry); - bool isEventFromReliableSourceLocked(EventEntry* entry); // Dispatch state. bool mDispatchEnabled; @@ -933,10 +973,10 @@ private: nsecs_t currentTime, ConfigurationChangedEntry* entry); bool dispatchKeyLocked( nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout, - bool dropEvent, nsecs_t* nextWakeupTime); + DropReason* dropReason, nsecs_t* nextWakeupTime); bool dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, - bool dropEvent, nsecs_t* nextWakeupTime); + DropReason* dropReason, nsecs_t* nextWakeupTime); void dispatchEventToCurrentInputTargetsLocked( nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample); @@ -995,11 +1035,17 @@ private: void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); - void abortDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - bool broken); + void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); void drainOutboundQueueLocked(Connection* connection); static int handleReceiveCallback(int receiveFd, int events, void* data); + void synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CancelationOptions options, const char* reason); + void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, + InputState::CancelationOptions options, const char* reason); + void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, + InputState::CancelationOptions options, const char* reason); + // Splitting motion events across windows. MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index 3619189..c15e382 100644 --- a/include/ui/InputReader.h +++ b/include/ui/InputReader.h @@ -87,49 +87,12 @@ public: ROTATION_270 = 3 }; - /* Actions returned by interceptXXX methods. */ - enum { - // The input dispatcher should do nothing and discard the input unless other - // flags are set. - ACTION_NONE = 0, - - // The input dispatcher should dispatch the input to the application. - ACTION_DISPATCH = 0x00000001, - }; - /* Gets information about the display with the specified id. * Returns true if the display info is available, false otherwise. */ virtual bool getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation) = 0; - /* Intercepts a key event. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * Returns a policy action constant such as ACTION_DISPATCH. - */ - virtual int32_t interceptKey(nsecs_t when, int32_t deviceId, - bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) = 0; - - /* Intercepts a switch event. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * Switches are not dispatched to applications so this method should - * usually return ACTION_NONE. - */ - virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, - uint32_t& policyFlags) = 0; - - /* Intercepts a generic touch, trackball or other event. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * Returns a policy action constant such as ACTION_DISPATCH. - */ - virtual int32_t interceptGeneric(nsecs_t when, uint32_t& policyFlags) = 0; - /* Determines whether to turn on some hacks we have to improve the touch interaction with a * certain device whose screen currently is not all that good. */ @@ -403,8 +366,6 @@ public: protected: InputDevice* mDevice; InputReaderContext* mContext; - - bool applyStandardPolicyActions(nsecs_t when, int32_t policyActions); }; @@ -466,8 +427,6 @@ private: void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags); - void applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, - bool down, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime); ssize_t findKeyDownLocked(int32_t scanCode); }; @@ -525,8 +484,6 @@ private: void initializeLocked(); void sync(nsecs_t when); - void applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction, - PointerCoords* pointerCoords, nsecs_t downTime); }; @@ -829,10 +786,6 @@ private: BitSet32 idBits, uint32_t changedId, uint32_t pointerCount, int32_t motionEventAction); - void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags, - int32_t keyCode, int32_t scanCode, nsecs_t downTime); - bool isPointInsideSurfaceLocked(int32_t x, int32_t y); const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 5b226b4..57de43a 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -43,6 +43,9 @@ namespace uirenderer { #define RAD_TO_DEG (180.0f / 3.14159265f) #define MIN_ANGLE 0.001f +// TODO: This should be set in properties +#define ALPHA_THRESHOLD (0x7f / PANEL_BIT_DEPTH) + /////////////////////////////////////////////////////////////////////////////// // Globals /////////////////////////////////////////////////////////////////////////////// @@ -294,7 +297,9 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, mode = SkXfermode::kSrcOver_Mode; } - createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo); + if (!mSnapshot->previous->invisible) { + createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo); + } return count; } @@ -380,6 +385,14 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, if (bounds.isEmpty() || bounds.getWidth() > mMaxTextureSize || bounds.getHeight() > mMaxTextureSize) { + snapshot->invisible = true; + } else { + // TODO: Should take the mode into account + snapshot->invisible = snapshot->previous->invisible || alpha <= ALPHA_THRESHOLD; + } + + // Bail out if we won't draw in this snapshot + if (snapshot->invisible) { return false; } @@ -536,7 +549,7 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { } void OpenGLRenderer::clearLayerRegions() { - if (mLayers.size() == 0) return; + if (mLayers.size() == 0 || mSnapshot->invisible) return; for (uint32_t i = 0; i < mLayers.size(); i++) { Rect* bounds = mLayers.itemAt(i); @@ -598,6 +611,10 @@ const Rect& OpenGLRenderer::getClipBounds() { } bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { + if (mSnapshot->invisible) { + return true; + } + Rect r(left, top, right, bottom); mSnapshot->transform->mapRect(r); return !mSnapshot->clipRect->intersects(r); @@ -703,6 +720,8 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int } void OpenGLRenderer::drawLines(float* points, int count, const SkPaint* paint) { + if (mSnapshot->invisible) return; + int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); @@ -802,6 +821,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { return; } + if (mSnapshot->invisible) return; paint->setAntiAlias(true); @@ -866,6 +886,8 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, } void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { + if (mSnapshot->invisible) return; + GLuint textureUnit = 0; glActiveTexture(gTextureUnits[textureUnit]); @@ -985,6 +1007,7 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t ProgramDescription description; description.hasTexture = true; description.hasAlpha8Texture = true; + const bool setColor = description.setAlpha8Color(r, g, b, a); if (applyFilters) { if (mShader) { @@ -1021,7 +1044,9 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t mModelView.loadIdentity(); } mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); - glUniform4f(mCaches.currentProgram->color, r, g, b, a); + if (setColor) { + mCaches.currentProgram->setColor(r, g, b, a); + } textureUnit++; if (applyFilters) { @@ -1126,6 +1151,8 @@ void OpenGLRenderer::setupColorRect(float left, float top, float right, float bo // Describe the required shaders ProgramDescription description; + const bool setColor = description.setColor(r, g, b, a); + if (mShader) { mShader->describe(description, mExtensions); } @@ -1152,7 +1179,7 @@ void OpenGLRenderer::setupColorRect(float left, float top, float right, float bo mat4 identity; mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity); } - glUniform4f(mCaches.currentProgram->color, r, g, b, a); + mCaches.currentProgram->setColor(r, g, b, a); // Setup attributes and uniforms required by the shaders if (mShader) { @@ -1189,6 +1216,7 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b ProgramDescription description; description.hasTexture = true; + const bool setColor = description.setColor(alpha, alpha, alpha, alpha); if (mColorFilter) { mColorFilter->describe(description, mExtensions); } @@ -1211,7 +1239,9 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); // Always premultiplied - glUniform4f(mCaches.currentProgram->color, alpha, alpha, alpha, alpha); + if (setColor) { + mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha); + } // Mesh int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp index 2e1b9a0..25674c6 100644 --- a/libs/hwui/Program.cpp +++ b/libs/hwui/Program.cpp @@ -58,7 +58,6 @@ Program::Program(const char* vertex, const char* fragment) { mUse = false; position = addAttrib("position"); - color = addUniform("color"); transform = addUniform("transform"); } @@ -124,6 +123,10 @@ void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]); } +void Program::setColor(const float r, const float g, const float b, const float a) { + glUniform4f(getUniform("color"), r, g, b, a); +} + void Program::use() { glUseProgram(id); mUse = true; diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index 6531c74..026097c 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -77,14 +77,14 @@ public: const mat4& transformMatrix); /** - * Name of the position attribute. + * Sets the color associated with this shader. */ - int position; + void setColor(const float r, const float g, const float b, const float a); /** - * Name of the color uniform. + * Name of the position attribute. */ - int color; + int position; /** * Name of the transform uniform. diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 439e6fb..1282b71 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -24,6 +24,14 @@ namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +#define MODULATE_OP_NO_MODULATE 0 +#define MODULATE_OP_MODULATE 1 +#define MODULATE_OP_MODULATE_A8 2 + +/////////////////////////////////////////////////////////////////////////////// // Vertex shaders snippets /////////////////////////////////////////////////////////////////////////////// @@ -50,7 +58,7 @@ const char* gVS_Header_Varyings_HasBitmap = "varying vec2 outBitmapTexCoords;\n"; const char* gVS_Header_Varyings_HasGradient[3] = { // Linear - "varying float index;\n", + "varying vec2 linear;\n", // Circular "varying vec2 circular;\n", // Sweep @@ -62,15 +70,14 @@ const char* gVS_Main_OutTexCoords = " outTexCoords = texCoords;\n"; const char* gVS_Main_OutGradient[3] = { // Linear - " index = (screenSpace * position).x;\n", + " linear = vec2((screenSpace * position).x, 0.5);\n", // Circular " circular = (screenSpace * position).xy;\n", // Sweep " sweep = (screenSpace * position).xy;\n" }; const char* gVS_Main_OutBitmapTexCoords = - " vec4 bitmapCoords = textureTransform * position;\n" - " outBitmapTexCoords = bitmapCoords.xy * textureDimension;\n"; + " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; const char* gVS_Main_Position = " gl_Position = transform * position;\n"; const char* gVS_Footer = @@ -113,15 +120,55 @@ const char* gFS_Uniforms_ColorOp[4] = { const char* gFS_Main = "\nvoid main(void) {\n" " lowp vec4 fragColor;\n"; + +// Fast cases +const char* gFS_Fast_SingleColor = + "\nvoid main(void) {\n" + " gl_FragColor = color;\n" + "}\n\n"; +const char* gFS_Fast_SingleTexture = + "\nvoid main(void) {\n" + " gl_FragColor = texture2D(sampler, outTexCoords);\n" + "}\n\n"; +const char* gFS_Fast_SingleModulateTexture = + "\nvoid main(void) {\n" + " gl_FragColor = color.a * texture2D(sampler, outTexCoords);\n" + "}\n\n"; +const char* gFS_Fast_SingleA8Texture = + "\nvoid main(void) {\n" + " gl_FragColor = vec4(0.0, 0.0, 0.0, texture2D(sampler, outTexCoords).a);\n" + "}\n\n"; +const char* gFS_Fast_SingleModulateA8Texture = + "\nvoid main(void) {\n" + " gl_FragColor = color * texture2D(sampler, outTexCoords).a;\n" + "}\n\n"; +const char* gFS_Fast_SingleGradient = + "\nvoid main(void) {\n" + " gl_FragColor = texture2D(gradientSampler, linear);\n" + "}\n\n"; +const char* gFS_Fast_SingleModulateGradient = + "\nvoid main(void) {\n" + " gl_FragColor = color.a * texture2D(gradientSampler, linear);\n" + "}\n\n"; + +// General case const char* gFS_Main_FetchColor = " fragColor = color;\n"; -const char* gFS_Main_FetchTexture = - " fragColor = color * texture2D(sampler, outTexCoords);\n"; -const char* gFS_Main_FetchA8Texture = - " fragColor = color * texture2D(sampler, outTexCoords).a;\n"; +const char* gFS_Main_FetchTexture[2] = { + // Don't modulate + " fragColor = texture2D(sampler, outTexCoords);\n", + // Modulate + " fragColor = color * texture2D(sampler, outTexCoords);\n" +}; +const char* gFS_Main_FetchA8Texture[2] = { + // Don't modulate + " fragColor = vec4(0.0, 0.0, 0.0, texture2D(sampler, outTexCoords).a);\n", + // Modulate + " fragColor = color * texture2D(sampler, outTexCoords).a;\n" +}; const char* gFS_Main_FetchGradient[3] = { // Linear - " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n", + " vec4 gradientColor = texture2D(gradientSampler, linear);\n", // Circular " float index = length(circular);\n" " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n", @@ -137,12 +184,30 @@ const char* gFS_Main_BlendShadersBG = " fragColor = blendShaders(gradientColor, bitmapColor)"; const char* gFS_Main_BlendShadersGB = " fragColor = blendShaders(bitmapColor, gradientColor)"; -const char* gFS_Main_BlendShaders_Modulate = - " * fragColor.a;\n"; -const char* gFS_Main_GradientShader_Modulate = - " fragColor = gradientColor * fragColor.a;\n"; -const char* gFS_Main_BitmapShader_Modulate = - " fragColor = bitmapColor * fragColor.a;\n"; +const char* gFS_Main_BlendShaders_Modulate[3] = { + // Don't modulate + ";\n", + // Modulate + " * fragColor.a;\n", + // Modulate with alpha 8 texture + " * texture2D(sampler, outTexCoords).a;\n" +}; +const char* gFS_Main_GradientShader_Modulate[3] = { + // Don't modulate + " fragColor = gradientColor;\n", + // Modulate + " fragColor = gradientColor * fragColor.a;\n", + // Modulate with alpha 8 texture + " fragColor = gradientColor * texture2D(sampler, outTexCoords).a;\n" + }; +const char* gFS_Main_BitmapShader_Modulate[3] = { + // Don't modulate + " fragColor = bitmapColor;\n", + // Modulate + " fragColor = bitmapColor * fragColor.a;\n", + // Modulate with alpha 8 texture + " fragColor = bitmapColor * texture2D(sampler, outTexCoords).a;\n" + }; const char* gFS_Main_FragColor = " gl_FragColor = fragColor;\n"; const char* gFS_Main_FragColor_Blend = @@ -317,7 +382,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // Set the default precision String8 shader; - bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode; + const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode; if (blendFramebuffer) { shader.append(gFS_Header_Extension_FramebufferFetch); } @@ -335,15 +400,72 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gVS_Header_Varyings_HasBitmap); } - // Uniforms - shader.append(gFS_Uniforms_Color); + int modulateOp = MODULATE_OP_NO_MODULATE; + const bool singleColor = !description.hasTexture && + !description.hasGradient && !description.hasBitmap; + + if (description.modulate || singleColor) { + shader.append(gFS_Uniforms_Color); + if (!singleColor) modulateOp = MODULATE_OP_MODULATE; + } if (description.hasTexture) { shader.append(gFS_Uniforms_TextureSampler); } if (description.hasGradient) { shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); } + + // Optimization for common cases + if (!blendFramebuffer) { + bool fast = false; + + const bool noShader = !description.hasGradient && !description.hasBitmap; + const bool singleTexture = description.hasTexture && + !description.hasAlpha8Texture && noShader; + const bool singleA8Texture = description.hasTexture && + description.hasAlpha8Texture && noShader; + const bool singleGradient = !description.hasTexture && + description.hasGradient && !description.hasBitmap && + description.gradientType == ProgramDescription::kGradientLinear; + + if (singleColor) { + shader.append(gFS_Fast_SingleColor); + fast = true; + } else if (singleTexture) { + if (!description.modulate) { + shader.append(gFS_Fast_SingleTexture); + } else { + shader.append(gFS_Fast_SingleModulateTexture); + } + fast = true; + } else if (singleA8Texture) { + if (!description.modulate) { + shader.append(gFS_Fast_SingleA8Texture); + } else { + shader.append(gFS_Fast_SingleModulateA8Texture); + } + fast = true; + } else if (singleGradient) { + if (!description.modulate) { + shader.append(gFS_Fast_SingleGradient); + } else { + shader.append(gFS_Fast_SingleModulateGradient); + } + fast = true; + } + + if (fast) { + if (DEBUG_PROGRAM_CACHE) { + PROGRAM_LOGD("*** Fast case:\n"); + PROGRAM_LOGD("*** Generated fragment shader:\n\n"); + printLongString(shader); + } + + return shader; + } + } + if (description.hasBitmap) { shader.append(gFS_Uniforms_BitmapSampler); } @@ -368,12 +490,16 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // Stores the result in fragColor directly if (description.hasTexture) { if (description.hasAlpha8Texture) { - shader.append(gFS_Main_FetchA8Texture); + if (!description.hasGradient && !description.hasBitmap) { + shader.append(gFS_Main_FetchA8Texture[modulateOp]); + } } else { - shader.append(gFS_Main_FetchTexture); + shader.append(gFS_Main_FetchTexture[modulateOp]); } } else { - shader.append(gFS_Main_FetchColor); + if ((!description.hasGradient && !description.hasBitmap) || description.modulate) { + shader.append(gFS_Main_FetchColor); + } } if (description.hasGradient) { shader.append(gFS_Main_FetchGradient[description.gradientType]); @@ -387,17 +513,20 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } // Case when we have two shaders set if (description.hasGradient && description.hasBitmap) { + int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; if (description.isBitmapFirst) { shader.append(gFS_Main_BlendShadersBG); } else { shader.append(gFS_Main_BlendShadersGB); } - shader.append(gFS_Main_BlendShaders_Modulate); + shader.append(gFS_Main_BlendShaders_Modulate[op]); } else { if (description.hasGradient) { - shader.append(gFS_Main_GradientShader_Modulate); + int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; + shader.append(gFS_Main_GradientShader_Modulate[op]); } else if (description.hasBitmap) { - shader.append(gFS_Main_BitmapShader_Modulate); + int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; + shader.append(gFS_Main_BitmapShader_Modulate[op]); } } // Apply the color op if needed diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index 4fa8011..ec9851e 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -44,6 +44,11 @@ namespace uirenderer { #define PROGRAM_LOGD(...) #endif +// TODO: This should be set in properties +#define PANEL_BIT_DEPTH 20 +#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH)) +#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH) + #define PROGRAM_KEY_TEXTURE 0x1 #define PROGRAM_KEY_A8_TEXTURE 0x2 #define PROGRAM_KEY_BITMAP 0x4 @@ -68,6 +73,7 @@ namespace uirenderer { #define PROGRAM_BITMAP_WRAPT_SHIFT 11 #define PROGRAM_GRADIENT_TYPE_SHIFT 33 +#define PROGRAM_MODULATE 35 /////////////////////////////////////////////////////////////////////////////// // Types @@ -99,7 +105,7 @@ struct ProgramDescription { }; ProgramDescription(): - hasTexture(false), hasAlpha8Texture(false), + hasTexture(false), hasAlpha8Texture(false), modulate(false), hasBitmap(false), isBitmapNpot(false), hasGradient(false), gradientType(kGradientLinear), shadersMode(SkXfermode::kClear_Mode), isBitmapFirst(false), @@ -112,6 +118,9 @@ struct ProgramDescription { bool hasTexture; bool hasAlpha8Texture; + // Modulate, this should only be set when setColor() return true + bool modulate; + // Shaders bool hasBitmap; bool isBitmapNpot; @@ -134,18 +143,31 @@ struct ProgramDescription { SkXfermode::Mode framebufferMode; bool swapSrcDst; - inline uint32_t getEnumForWrap(GLenum wrap) const { - switch (wrap) { - case GL_CLAMP_TO_EDGE: - return 0; - case GL_REPEAT: - return 1; - case GL_MIRRORED_REPEAT: - return 2; - } - return 0; + /** + * Indicates, for a given color, whether color modulation is required in + * the fragment shader. When this method returns true, the program should + * be provided with a modulation color. + */ + bool setColor(const float r, const float g, const float b, const float a) { + modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD || + g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD; + return modulate; + } + + /** + * Indicates, for a given color, whether color modulation is required in + * the fragment shader. When this method returns true, the program should + * be provided with a modulation color. + */ + bool setAlpha8Color(const float r, const float g, const float b, const float a) { + modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD || + g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD; + return modulate; } + /** + * Computes the unique key identifying this program. + */ programid key() const { programid key = 0; if (hasTexture) key |= PROGRAM_KEY_TEXTURE; @@ -180,14 +202,32 @@ struct ProgramDescription { } key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT; if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; + if (modulate) key |= programid(0x1) << PROGRAM_MODULATE; return key; } + /** + * Logs the specified message followed by the key identifying this program. + */ void log(const char* message) const { programid k = key(); PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32), uint32_t(k & 0xffffffff)); } + +private: + inline uint32_t getEnumForWrap(GLenum wrap) const { + switch (wrap) { + case GL_CLAMP_TO_EDGE: + return 0; + case GL_REPEAT: + return 1; + case GL_MIRRORED_REPEAT: + return 2; + } + return 0; + } + }; // struct ProgramDescription /** diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index 3d74b4c..35cdf6f 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -43,7 +43,7 @@ namespace uirenderer { */ class Snapshot: public LightRefBase<Snapshot> { public: - Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0) { + Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), invisible(false) { transform = &mTransformRoot; clipRect = &mClipRectRoot; } @@ -53,8 +53,8 @@ public: * the previous snapshot. */ Snapshot(const sp<Snapshot>& s, int saveFlags): - flags(0), previous(s), layer(NULL), - fbo(s->fbo), viewport(s->viewport), height(s->height) { + flags(0), previous(s), layer(NULL), fbo(s->fbo), + invisible(s->invisible), viewport(s->viewport), height(s->height) { if (saveFlags & SkCanvas::kMatrix_SaveFlag) { mTransformRoot.load(*s->transform); transform = &mTransformRoot; @@ -212,6 +212,12 @@ public: GLuint fbo; /** + * Indicates that this snapshot is invisible and nothing should be drawn + * inside it. + */ + bool invisible; + + /** * Current viewport. */ Rect viewport; diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java b/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java index 32b55d9..da995da 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java +++ b/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java @@ -58,18 +58,30 @@ public class UT_primitives extends UnitTest { } s.set_intTest(-64); - /*long pL = s.get_longTest(); + long pL = s.get_longTest(); if (pL != 17179869184l) { return false; } - s.set_longTest(17179869185l);*/ + s.set_longTest(17179869185l); + + long puL = s.get_ulongTest(); + if (puL != 4611686018427387904L) { + return false; + } + s.set_ulongTest(4611686018427387903L); + long pLL = s.get_longlongTest(); if (pLL != 68719476736L) { return false; } s.set_longlongTest(68719476735L); - //s.set_longlongTest(0); + + long pu64 = s.get_uint64_tTest(); + if (pu64 != 117179869184l) { + return false; + } + s.set_uint64_tTest(117179869185l); return true; } diff --git a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs index 2db82da..351a8a5 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs +++ b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs @@ -14,7 +14,9 @@ long long longlongTest = 68719476736l; // 1 << 36 uchar ucharTest = 8; ushort ushortTest = 16; uint uintTest = 32; +ulong ulongTest = 4611686018427387904L; int64_t int64_tTest = -17179869184l; // - 1 << 34 +uint64_t uint64_tTest = 117179869184l; static bool test_primitive_types(uint32_t index) { bool failed = false; @@ -25,13 +27,15 @@ static bool test_primitive_types(uint32_t index) { _RS_ASSERT(charTest == -16); _RS_ASSERT(shortTest == -32); _RS_ASSERT(intTest == -64); - _RS_ASSERT(longTest == 17179869184l); + _RS_ASSERT(longTest == 17179869185l); _RS_ASSERT(longlongTest == 68719476735l); _RS_ASSERT(ucharTest == 8); _RS_ASSERT(ushortTest == 16); _RS_ASSERT(uintTest == 32); + _RS_ASSERT(ulongTest == 4611686018427387903L); _RS_ASSERT(int64_tTest == -17179869184l); + _RS_ASSERT(uint64_tTest == 117179869185l); float time = end(index); diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 75b2294..52e488a 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -95,16 +95,19 @@ static bool validateKeyEvent(int32_t action) { return true; } -static bool isValidMotionAction(int32_t action) { +static bool isValidMotionAction(int32_t action, size_t pointerCount) { switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: case AMOTION_EVENT_ACTION_OUTSIDE: return true; + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_POINTER_UP: { + int32_t index = getMotionEventActionPointerIndex(action); + return index >= 0 && size_t(index) < pointerCount; + } default: return false; } @@ -112,7 +115,7 @@ static bool isValidMotionAction(int32_t action) { static bool validateMotionEvent(int32_t action, size_t pointerCount, const int32_t* pointerIds) { - if (! isValidMotionAction(action)) { + if (! isValidMotionAction(action, pointerCount)) { LOGE("Motion event has invalid action code 0x%x", action); return false; } @@ -235,16 +238,6 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, resetKeyRepeatLocked(); } - // If dispatching is disabled, drop all events in the queue. - if (! mDispatchEnabled) { - if (mPendingEvent || ! mInboundQueue.isEmpty()) { - LOGI("Dropping pending events because input dispatch is disabled."); - releasePendingEventLocked(); - drainInboundQueueLocked(); - } - return; - } - // If dispatching is frozen, do not process timeouts or try to deliver any new events. if (mDispatchFrozen) { #if DEBUG_FOCUS @@ -294,7 +287,11 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, // samples may be appended to this event by the time the throttling timeout // expires. // TODO Make this smarter and consider throttling per device independently. - if (entry->type == EventEntry::TYPE_MOTION) { + if (entry->type == EventEntry::TYPE_MOTION + && !isAppSwitchDue + && mDispatchEnabled + && (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) + && !entry->isInjected()) { MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); int32_t deviceId = motionEntry->deviceId; uint32_t source = motionEntry->source; @@ -347,39 +344,43 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, // Now we have an event to dispatch. assert(mPendingEvent != NULL); bool done = false; + DropReason dropReason = DROP_REASON_NOT_DROPPED; + if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { + dropReason = DROP_REASON_POLICY; + } else if (!mDispatchEnabled) { + dropReason = DROP_REASON_DISABLED; + } switch (mPendingEvent->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = static_cast<ConfigurationChangedEntry*>(mPendingEvent); done = dispatchConfigurationChangedLocked(currentTime, typedEntry); + dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped break; } case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); - bool appSwitchKey = isAppSwitchKey(typedEntry->keyCode); - bool dropEvent = isAppSwitchDue && ! appSwitchKey; - done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, dropEvent, - nextWakeupTime); - if (done) { - if (dropEvent) { - LOGI("Dropped key because of pending overdue app switch."); - } else if (appSwitchKey) { + if (isAppSwitchDue) { + if (isAppSwitchKeyEventLocked(typedEntry)) { resetPendingAppSwitchLocked(true); + isAppSwitchDue = false; + } else if (dropReason == DROP_REASON_NOT_DROPPED) { + dropReason = DROP_REASON_APP_SWITCH; } } + done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, + &dropReason, nextWakeupTime); break; } case EventEntry::TYPE_MOTION: { MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); - bool dropEvent = isAppSwitchDue; - done = dispatchMotionLocked(currentTime, typedEntry, dropEvent, nextWakeupTime); - if (done) { - if (dropEvent) { - LOGI("Dropped motion because of pending overdue app switch."); - } + if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { + dropReason = DROP_REASON_APP_SWITCH; } + done = dispatchMotionLocked(currentTime, typedEntry, + &dropReason, nextWakeupTime); break; } @@ -389,6 +390,10 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, } if (done) { + if (dropReason != DROP_REASON_NOT_DROPPED) { + dropInboundEventLocked(mPendingEvent, dropReason); + } + releasePendingEventLocked(); *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } @@ -399,34 +404,84 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { mInboundQueue.enqueueAtTail(entry); switch (entry->type) { - case EventEntry::TYPE_KEY: - needWake |= detectPendingAppSwitchLocked(static_cast<KeyEntry*>(entry)); + case EventEntry::TYPE_KEY: { + KeyEntry* keyEntry = static_cast<KeyEntry*>(entry); + if (isAppSwitchKeyEventLocked(keyEntry)) { + if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { + mAppSwitchSawKeyDown = true; + } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { + if (mAppSwitchSawKeyDown) { +#if DEBUG_APP_SWITCH + LOGD("App switch is pending!"); +#endif + mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; + mAppSwitchSawKeyDown = false; + needWake = true; + } + } + } break; } + } return needWake; } -bool InputDispatcher::isAppSwitchKey(int32_t keyCode) { +void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { + const char* reason; + switch (dropReason) { + case DROP_REASON_POLICY: +#if DEBUG_INBOUND_EVENT_DETAILS + LOGD("Dropped event because policy requested that it not be delivered to the application."); +#endif + reason = "inbound event was dropped because the policy requested that it not be " + "delivered to the application"; + break; + case DROP_REASON_DISABLED: + LOGI("Dropped event because input dispatch is disabled."); + reason = "inbound event was dropped because input dispatch is disabled"; + break; + case DROP_REASON_APP_SWITCH: + LOGI("Dropped event because of pending overdue app switch."); + reason = "inbound event was dropped because of pending overdue app switch"; + break; + default: + assert(false); + return; + } + + switch (entry->type) { + case EventEntry::TYPE_KEY: + synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CANCEL_NON_POINTER_EVENTS, reason); + break; + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); + if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { + synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CANCEL_POINTER_EVENTS, reason); + } else { + synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CANCEL_NON_POINTER_EVENTS, reason); + } + break; + } + } +} + +bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) { return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL; } -bool InputDispatcher::isAppSwitchPendingLocked() { - return mAppSwitchDueTime != LONG_LONG_MAX; +bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) { + return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) + && isAppSwitchKeyCode(keyEntry->keyCode) + && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) + && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); } -bool InputDispatcher::detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry) { - if (inboundKeyEntry->action == AKEY_EVENT_ACTION_UP - && ! (inboundKeyEntry->flags & AKEY_EVENT_FLAG_CANCELED) - && isAppSwitchKey(inboundKeyEntry->keyCode) - && isEventFromReliableSourceLocked(inboundKeyEntry)) { -#if DEBUG_APP_SWITCH - LOGD("App switch is pending!"); -#endif - mAppSwitchDueTime = inboundKeyEntry->eventTime + APP_SWITCH_TIMEOUT; - return true; // need wake - } - return false; +bool InputDispatcher::isAppSwitchPendingLocked() { + return mAppSwitchDueTime != LONG_LONG_MAX; } void InputDispatcher::resetPendingAppSwitchLocked(bool handled) { @@ -489,14 +544,6 @@ void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) { mAllocator.releaseEventEntry(entry); } -bool InputDispatcher::isEventFromReliableSourceLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - return ! injectionState - || injectionState->injectorUid == 0 - || mPolicy->checkInjectEventsPermissionNonReentrant( - injectionState->injectorPid, injectionState->injectorUid); -} - void InputDispatcher::resetKeyRepeatLocked() { if (mKeyRepeatState.lastKeyEntry) { mAllocator.releaseKeyEntry(mKeyRepeatState.lastKeyEntry); @@ -509,7 +556,8 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked( KeyEntry* entry = mKeyRepeatState.lastKeyEntry; // Reuse the repeated key entry if it is otherwise unreferenced. - uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK; + uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK) + | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED; if (entry->refCount == 1) { mAllocator.recycleKeyEntry(entry); entry->eventTime = currentTime; @@ -558,19 +606,13 @@ bool InputDispatcher::dispatchConfigurationChangedLocked( bool InputDispatcher::dispatchKeyLocked( nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout, - bool dropEvent, nsecs_t* nextWakeupTime) { + DropReason* dropReason, nsecs_t* nextWakeupTime) { // Give the policy a chance to intercept the key. if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { - bool trusted; - if (! dropEvent && mFocusedWindow) { - trusted = checkInjectionPermission(mFocusedWindow, entry->injectionState); - } else { - trusted = isEventFromReliableSourceLocked(entry); - } - if (trusted) { + if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); - if (! dropEvent && mFocusedWindow) { + if (mFocusedWindow) { commandEntry->inputChannel = mFocusedWindow->inputChannel; } commandEntry->keyEntry = entry; @@ -580,13 +622,16 @@ bool InputDispatcher::dispatchKeyLocked( entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { + if (*dropReason == DROP_REASON_NOT_DROPPED) { + *dropReason = DROP_REASON_POLICY; + } resetTargetsLocked(); setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_SUCCEEDED); return true; } // Clean up if dropping the event. - if (dropEvent) { + if (*dropReason != DROP_REASON_NOT_DROPPED) { resetTargetsLocked(); setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED); return true; @@ -598,7 +643,8 @@ bool InputDispatcher::dispatchKeyLocked( if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN - && ! entry->isInjected()) { + && (entry->policyFlags & POLICY_FLAG_TRUSTED) + && !entry->isInjected()) { if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { // We have seen two identical key downs in a row which indicates that the device @@ -663,9 +709,9 @@ void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyE } bool InputDispatcher::dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, bool dropEvent, nsecs_t* nextWakeupTime) { + nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // Clean up if dropping the event. - if (dropEvent) { + if (*dropReason != DROP_REASON_NOT_DROPPED) { resetTargetsLocked(); setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED); return true; @@ -793,9 +839,11 @@ void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTi prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget, resumeWithAppendedMotionSample); } else { - LOGW("Framework requested delivery of an input event to channel '%s' but it " - "is not registered with the input dispatcher.", +#if DEBUG_FOCUS + LOGD("Dropping event delivery to target with channel '%s' because it " + "is no longer registered with the input dispatcher.", inputTarget.inputChannel->getName().string()); +#endif } } } @@ -876,7 +924,9 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); if (connectionIndex >= 0) { sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); - connection->inputState.setOutOfSync(); + synthesizeCancelationEventsForConnectionLocked( + connection, InputState::CANCEL_ALL_EVENTS, + "application not responding"); } } } @@ -1236,7 +1286,9 @@ Failed: } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { // First pointer went down. if (mTouchState.down) { - LOGW("Pointer down received while already down."); +#if DEBUG_FOCUS + LOGD("Pointer down received while already down."); +#endif } } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { // One pointer went up. @@ -1307,23 +1359,19 @@ void InputDispatcher::addMonitoringTargetsLocked() { bool InputDispatcher::checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState) { if (injectionState - && injectionState->injectorUid > 0 - && (window == NULL || window->ownerUid != injectionState->injectorUid)) { - bool result = mPolicy->checkInjectEventsPermissionNonReentrant( - injectionState->injectorPid, injectionState->injectorUid); - if (! result) { - if (window) { - LOGW("Permission denied: injecting event from pid %d uid %d to window " - "with input channel %s owned by uid %d", - injectionState->injectorPid, injectionState->injectorUid, - window->inputChannel->getName().string(), - window->ownerUid); - } else { - LOGW("Permission denied: injecting event from pid %d uid %d", - injectionState->injectorPid, injectionState->injectorUid); - } - return false; + && (window == NULL || window->ownerUid != injectionState->injectorUid) + && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { + if (window) { + LOGW("Permission denied: injecting event from pid %d uid %d to window " + "with input channel %s owned by uid %d", + injectionState->injectorPid, injectionState->injectorUid, + window->inputChannel->getName().string(), + window->ownerUid); + } else { + LOGW("Permission denied: injecting event from pid %d uid %d", + injectionState->injectorPid, injectionState->injectorUid); } + return false; } return true; } @@ -1408,8 +1456,10 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, // Skip this event if the connection status is not normal. // We don't want to enqueue additional outbound events if the connection is broken. if (connection->status != Connection::STATUS_NORMAL) { - LOGW("channel '%s' ~ Dropping event because the channel status is %s", +#if DEBUG_DISPATCH_CYCLE + LOGD("channel '%s' ~ Dropping event because the channel status is %s", connection->getInputChannelName(), connection->getStatusLabel()); +#endif return; } @@ -1508,40 +1558,6 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, } } - // Bring the input state back in line with reality in case it drifted off during an ANR. - if (connection->inputState.isOutOfSync()) { - mTempCancelationEvents.clear(); - connection->inputState.synthesizeCancelationEvents(& mAllocator, mTempCancelationEvents); - connection->inputState.resetOutOfSync(); - - if (! mTempCancelationEvents.isEmpty()) { - LOGI("channel '%s' ~ Generated %d cancelation events to bring channel back in sync " - "with reality.", - connection->getInputChannelName(), mTempCancelationEvents.size()); - - for (size_t i = 0; i < mTempCancelationEvents.size(); i++) { - EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i); - switch (cancelationEventEntry->type) { - case EventEntry::TYPE_KEY: - logOutboundKeyDetailsLocked(" ", - static_cast<KeyEntry*>(cancelationEventEntry)); - break; - case EventEntry::TYPE_MOTION: - logOutboundMotionDetailsLocked(" ", - static_cast<MotionEntry*>(cancelationEventEntry)); - break; - } - - DispatchEntry* cancelationDispatchEntry = - mAllocator.obtainDispatchEntry(cancelationEventEntry, - 0, inputTarget->xOffset, inputTarget->yOffset); // increments ref - connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry); - - mAllocator.releaseEventEntry(cancelationEventEntry); - } - } - } - // This is a new event. // Enqueue a new dispatch entry onto the outbound queue for this connection. DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref @@ -1635,7 +1651,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, if (status) { LOGE("channel '%s' ~ Could not publish key event, " "status=%d", connection->getInputChannelName(), status); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); return; } break; @@ -1685,7 +1701,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, if (status) { LOGE("channel '%s' ~ Could not publish motion event, " "status=%d", connection->getInputChannelName(), status); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); return; } @@ -1706,7 +1722,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, LOGE("channel '%s' ~ Could not append motion sample " "for a reason other than out of memory, status=%d", connection->getInputChannelName(), status); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); return; } } @@ -1727,7 +1743,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, if (status) { LOGE("channel '%s' ~ Could not send dispatch signal, status=%d", connection->getInputChannelName(), status); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); return; } @@ -1764,7 +1780,7 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, if (status) { LOGE("channel '%s' ~ Could not reset publisher, status=%d", connection->getInputChannelName(), status); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); return; } @@ -1806,28 +1822,23 @@ void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime, deactivateConnectionLocked(connection.get()); } -void InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, bool broken) { +void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, + const sp<Connection>& connection) { #if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ abortDispatchCycle - broken=%s", + LOGD("channel '%s' ~ abortBrokenDispatchCycle - broken=%s", connection->getInputChannelName(), toString(broken)); #endif - // Input state will no longer be realistic. - connection->inputState.setOutOfSync(); - // Clear the outbound queue. drainOutboundQueueLocked(connection.get()); - // Handle the case where the connection appears to be unrecoverably broken. + // The connection appears to be unrecoverably broken. // Ignore already broken or zombie connections. - if (broken) { - if (connection->status == Connection::STATUS_NORMAL) { - connection->status = Connection::STATUS_BROKEN; + if (connection->status == Connection::STATUS_NORMAL) { + connection->status = Connection::STATUS_BROKEN; - // Notify other system components. - onDispatchCycleBrokenLocked(currentTime, connection); - } + // Notify other system components. + onDispatchCycleBrokenLocked(currentTime, connection); } } @@ -1862,7 +1873,7 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. " "events=0x%x", connection->getInputChannelName(), events); - d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + d->abortBrokenDispatchCycleLocked(currentTime, connection); d->runCommandsLockedInterruptible(); return 0; // remove the callback } @@ -1877,7 +1888,7 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data if (status) { LOGE("channel '%s' ~ Failed to receive finished signal. status=%d", connection->getInputChannelName(), status); - d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + d->abortBrokenDispatchCycleLocked(currentTime, connection); d->runCommandsLockedInterruptible(); return 0; // remove the callback } @@ -1888,6 +1899,77 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data } // release lock } +void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CancelationOptions options, const char* reason) { + for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) { + synthesizeCancelationEventsForConnectionLocked( + mConnectionsByReceiveFd.valueAt(i), options, reason); + } +} + +void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( + const sp<InputChannel>& channel, InputState::CancelationOptions options, + const char* reason) { + ssize_t index = getConnectionIndexLocked(channel); + if (index >= 0) { + synthesizeCancelationEventsForConnectionLocked( + mConnectionsByReceiveFd.valueAt(index), options, reason); + } +} + +void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( + const sp<Connection>& connection, InputState::CancelationOptions options, + const char* reason) { + nsecs_t currentTime = now(); + + mTempCancelationEvents.clear(); + connection->inputState.synthesizeCancelationEvents(currentTime, & mAllocator, + mTempCancelationEvents, options); + + if (! mTempCancelationEvents.isEmpty() + && connection->status != Connection::STATUS_BROKEN) { +#if DEBUG_OUTBOUND_EVENT_DETAILS + LOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync " + "with reality: %s, options=%d.", + connection->getInputChannelName(), mTempCancelationEvents.size(), reason, options); +#endif + for (size_t i = 0; i < mTempCancelationEvents.size(); i++) { + EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i); + switch (cancelationEventEntry->type) { + case EventEntry::TYPE_KEY: + logOutboundKeyDetailsLocked("cancel - ", + static_cast<KeyEntry*>(cancelationEventEntry)); + break; + case EventEntry::TYPE_MOTION: + logOutboundMotionDetailsLocked("cancel - ", + static_cast<MotionEntry*>(cancelationEventEntry)); + break; + } + + int32_t xOffset, yOffset; + const InputWindow* window = getWindowLocked(connection->inputChannel); + if (window) { + xOffset = -window->frameLeft; + yOffset = -window->frameTop; + } else { + xOffset = 0; + yOffset = 0; + } + + DispatchEntry* cancelationDispatchEntry = + mAllocator.obtainDispatchEntry(cancelationEventEntry, // increments ref + 0, xOffset, yOffset); + connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry); + + mAllocator.releaseEventEntry(cancelationEventEntry); + } + + if (!connection->outboundQueue.headSentinel.next->inProgress) { + startDispatchCycleLocked(currentTime, connection); + } + } +} + InputDispatcher::MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { assert(pointerIds.value != 0); @@ -1999,6 +2081,10 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t sou return; } + policyFlags |= POLICY_FLAG_TRUSTED; + mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags, + keyCode, scanCode, /*byref*/ policyFlags); + bool needWake; { // acquire lock AutoMutex _l(mLock); @@ -2041,6 +2127,9 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t return; } + policyFlags |= POLICY_FLAG_TRUSTED; + mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags); + bool needWake; { // acquire lock AutoMutex _l(mLock); @@ -2165,6 +2254,17 @@ NoBatchingOrStreaming:; } } +void InputDispatcher::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, + uint32_t policyFlags) { +#if DEBUG_INBOUND_EVENT_DETAILS + LOGD("notifySwitch - switchCode=%d, switchValue=%d, policyFlags=0x%x", + switchCode, switchValue, policyFlags); +#endif + + policyFlags |= POLICY_FLAG_TRUSTED; + mPolicy->notifySwitch(when, switchCode, switchValue, policyFlags); +} + int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) { #if DEBUG_INBOUND_EVENT_DETAILS @@ -2175,26 +2275,81 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); - InjectionState* injectionState; - bool needWake; - { // acquire lock - AutoMutex _l(mLock); + uint32_t policyFlags = POLICY_FLAG_INJECTED; + if (hasInjectionPermission(injectorPid, injectorUid)) { + policyFlags |= POLICY_FLAG_TRUSTED; + } - EventEntry* injectedEntry = createEntryFromInjectedInputEventLocked(event); - if (! injectedEntry) { + EventEntry* injectedEntry; + switch (event->getType()) { + case AINPUT_EVENT_TYPE_KEY: { + const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event); + int32_t action = keyEvent->getAction(); + if (! validateKeyEvent(action)) { return INPUT_EVENT_INJECTION_FAILED; } - injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid); - if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { - injectionState->injectionIsAsync = true; + nsecs_t eventTime = keyEvent->getEventTime(); + int32_t deviceId = keyEvent->getDeviceId(); + int32_t flags = keyEvent->getFlags(); + int32_t keyCode = keyEvent->getKeyCode(); + int32_t scanCode = keyEvent->getScanCode(); + mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags, + keyCode, scanCode, /*byref*/ policyFlags); + + mLock.lock(); + injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(), + policyFlags, action, flags, keyCode, scanCode, keyEvent->getMetaState(), + keyEvent->getRepeatCount(), keyEvent->getDownTime()); + break; + } + + case AINPUT_EVENT_TYPE_MOTION: { + const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); + int32_t action = motionEvent->getAction(); + size_t pointerCount = motionEvent->getPointerCount(); + const int32_t* pointerIds = motionEvent->getPointerIds(); + if (! validateMotionEvent(action, pointerCount, pointerIds)) { + return INPUT_EVENT_INJECTION_FAILED; } - injectionState->refCount += 1; - injectedEntry->injectionState = injectionState; + nsecs_t eventTime = motionEvent->getEventTime(); + mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags); - needWake = enqueueInboundEventLocked(injectedEntry); - } // release lock + mLock.lock(); + const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); + const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); + MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, + action, motionEvent->getFlags(), + motionEvent->getMetaState(), motionEvent->getEdgeFlags(), + motionEvent->getXPrecision(), motionEvent->getYPrecision(), + motionEvent->getDownTime(), uint32_t(pointerCount), + pointerIds, samplePointerCoords); + for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { + sampleEventTimes += 1; + samplePointerCoords += pointerCount; + mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords); + } + injectedEntry = motionEntry; + break; + } + + default: + LOGW("Cannot inject event of type %d", event->getType()); + return INPUT_EVENT_INJECTION_FAILED; + } + + InjectionState* injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid); + if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { + injectionState->injectionIsAsync = true; + } + + injectionState->refCount += 1; + injectedEntry->injectionState = injectionState; + + bool needWake = enqueueInboundEventLocked(injectedEntry); + mLock.unlock(); if (needWake) { mLooper->wake(); @@ -2260,6 +2415,11 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, return injectionResult; } +bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { + return injectorUid == 0 + || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); +} + void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) { InjectionState* injectionState = entry->injectionState; if (injectionState) { @@ -2310,59 +2470,6 @@ void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* ent } } -InputDispatcher::EventEntry* InputDispatcher::createEntryFromInjectedInputEventLocked( - const InputEvent* event) { - switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: { - const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event); - if (! validateKeyEvent(keyEvent->getAction())) { - return NULL; - } - - uint32_t policyFlags = POLICY_FLAG_INJECTED; - - KeyEntry* keyEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(), - keyEvent->getDeviceId(), keyEvent->getSource(), policyFlags, - keyEvent->getAction(), keyEvent->getFlags(), - keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(), - keyEvent->getRepeatCount(), keyEvent->getDownTime()); - return keyEntry; - } - - case AINPUT_EVENT_TYPE_MOTION: { - const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); - if (! validateMotionEvent(motionEvent->getAction(), - motionEvent->getPointerCount(), motionEvent->getPointerIds())) { - return NULL; - } - - uint32_t policyFlags = POLICY_FLAG_INJECTED; - - const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); - const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - size_t pointerCount = motionEvent->getPointerCount(); - - MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - motionEvent->getAction(), motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), uint32_t(pointerCount), - motionEvent->getPointerIds(), samplePointerCoords); - for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { - sampleEventTimes += 1; - samplePointerCoords += pointerCount; - mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords); - } - return motionEntry; - } - - default: - assert(false); - return NULL; - } -} - const InputWindow* InputDispatcher::getWindowLocked(const sp<InputChannel>& inputChannel) { for (size_t i = 0; i < mWindows.size(); i++) { const InputWindow* window = & mWindows[i]; @@ -2381,7 +2488,12 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) { AutoMutex _l(mLock); // Clear old window pointers. - mFocusedWindow = NULL; + sp<InputChannel> oldFocusedWindowChannel; + if (mFocusedWindow) { + oldFocusedWindowChannel = mFocusedWindow->inputChannel; + mFocusedWindow = NULL; + } + mWindows.clear(); // Loop over new windows and rebuild the necessary window pointers for @@ -2397,6 +2509,24 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) { } } + if (oldFocusedWindowChannel != NULL) { + if (!mFocusedWindow || oldFocusedWindowChannel != mFocusedWindow->inputChannel) { +#if DEBUG_FOCUS + LOGD("Focus left window: %s", + oldFocusedWindowChannel->getName().string()); +#endif + synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel, + InputState::CANCEL_NON_POINTER_EVENTS, "focus left window"); + oldFocusedWindowChannel.clear(); + } + } + if (mFocusedWindow && oldFocusedWindowChannel == NULL) { +#if DEBUG_FOCUS + LOGD("Focus entered window: %s", + mFocusedWindow->inputChannel->getName().string()); +#endif + } + for (size_t i = 0; i < mTouchState.windows.size(); ) { TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i); const InputWindow* window = getWindowLocked(touchedWindow.channel); @@ -2404,12 +2534,17 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) { touchedWindow.window = window; i += 1; } else { +#if DEBUG_FOCUS + LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string()); +#endif mTouchState.windows.removeAt(i); + synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel, + InputState::CANCEL_POINTER_EVENTS, "touched window was removed"); } } #if DEBUG_FOCUS - logDispatchStateLocked(); + //logDispatchStateLocked(); #endif } // release lock @@ -2432,7 +2567,7 @@ void InputDispatcher::setFocusedApplication(const InputApplication* inputApplica } #if DEBUG_FOCUS - logDispatchStateLocked(); + //logDispatchStateLocked(); #endif } // release lock @@ -2469,7 +2604,7 @@ void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { } #if DEBUG_FOCUS - logDispatchStateLocked(); + //logDispatchStateLocked(); #endif } // release lock @@ -2533,6 +2668,18 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, return false; } + ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); + ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); + if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { + sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex); + sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex); + + fromConnection->inputState.copyPointerStateTo(toConnection->inputState); + synthesizeCancelationEventsForConnectionLocked(fromConnection, + InputState::CANCEL_POINTER_EVENTS, + "transferring touch focus from this window to another window"); + } + #if DEBUG_FOCUS logDispatchStateLocked(); #endif @@ -2635,11 +2782,10 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { for (size_t i = 0; i < mActiveConnections.size(); i++) { const Connection* connection = mActiveConnections[i]; dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u" - "inputState.isNeutral=%s, inputState.isOutOfSync=%s\n", + "inputState.isNeutral=%s\n", i, connection->getInputChannelName(), connection->getStatusLabel(), connection->outboundQueue.count(), - toString(connection->inputState.isNeutral()), - toString(connection->inputState.isOutOfSync())); + toString(connection->inputState.isNeutral())); } } else { dump.append(INDENT "ActiveConnections: <none>\n"); @@ -2720,7 +2866,7 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh mLooper->removeFd(inputChannel->getReceivePipeFd()); nsecs_t currentTime = now(); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); runCommandsLockedInterruptible(); } // release lock @@ -2901,11 +3047,12 @@ InputDispatcher::Allocator::obtainInjectionState(int32_t injectorPid, int32_t in } void InputDispatcher::Allocator::initializeEventEntry(EventEntry* entry, int32_t type, - nsecs_t eventTime) { + nsecs_t eventTime, uint32_t policyFlags) { entry->type = type; entry->refCount = 1; entry->dispatchInProgress = false; entry->eventTime = eventTime; + entry->policyFlags = policyFlags; entry->injectionState = NULL; } @@ -2919,7 +3066,7 @@ void InputDispatcher::Allocator::releaseEventEntryInjectionState(EventEntry* ent InputDispatcher::ConfigurationChangedEntry* InputDispatcher::Allocator::obtainConfigurationChangedEntry(nsecs_t eventTime) { ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime); + initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime, 0); return entry; } @@ -2928,11 +3075,10 @@ InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry(nsecs_t ev int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime) { KeyEntry* entry = mKeyEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime); + initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime, policyFlags); entry->deviceId = deviceId; entry->source = source; - entry->policyFlags = policyFlags; entry->action = action; entry->flags = flags; entry->keyCode = keyCode; @@ -2951,12 +3097,11 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsec nsecs_t downTime, uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords) { MotionEntry* entry = mMotionEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime); + initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime, policyFlags); entry->eventTime = eventTime; entry->deviceId = deviceId; entry->source = source; - entry->policyFlags = policyFlags; entry->action = action; entry->flags = flags; entry->metaState = metaState; @@ -3103,8 +3248,7 @@ uint32_t InputDispatcher::MotionEntry::countSamples() const { // --- InputDispatcher::InputState --- -InputDispatcher::InputState::InputState() : - mIsOutOfSync(false) { +InputDispatcher::InputState::InputState() { } InputDispatcher::InputState::~InputState() { @@ -3114,20 +3258,6 @@ bool InputDispatcher::InputState::isNeutral() const { return mKeyMementos.isEmpty() && mMotionMementos.isEmpty(); } -bool InputDispatcher::InputState::isOutOfSync() const { - return mIsOutOfSync; -} - -void InputDispatcher::InputState::setOutOfSync() { - if (! isNeutral()) { - mIsOutOfSync = true; - } -} - -void InputDispatcher::InputState::resetOutOfSync() { - mIsOutOfSync = false; -} - InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackEvent( const EventEntry* entry) { switch (entry->type) { @@ -3154,9 +3284,6 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackKey( switch (action) { case AKEY_EVENT_ACTION_UP: mKeyMementos.removeAt(i); - if (isNeutral()) { - mIsOutOfSync = false; - } return CONSISTENT; case AKEY_EVENT_ACTION_DOWN: @@ -3196,9 +3323,6 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackMotio case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: mMotionMementos.removeAt(i); - if (isNeutral()) { - mIsOutOfSync = false; - } return CONSISTENT; case AMOTION_EVENT_ACTION_DOWN: @@ -3256,30 +3380,70 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* } } -void InputDispatcher::InputState::synthesizeCancelationEvents( - Allocator* allocator, Vector<EventEntry*>& outEvents) const { - for (size_t i = 0; i < mKeyMementos.size(); i++) { +void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, + Allocator* allocator, Vector<EventEntry*>& outEvents, + CancelationOptions options) { + for (size_t i = 0; i < mKeyMementos.size(); ) { const KeyMemento& memento = mKeyMementos.itemAt(i); - outEvents.push(allocator->obtainKeyEntry(now(), - memento.deviceId, memento.source, 0, - AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED, - memento.keyCode, memento.scanCode, 0, 0, memento.downTime)); + if (shouldCancelEvent(memento.source, options)) { + outEvents.push(allocator->obtainKeyEntry(currentTime, + memento.deviceId, memento.source, 0, + AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED, + memento.keyCode, memento.scanCode, 0, 0, memento.downTime)); + mKeyMementos.removeAt(i); + } else { + i += 1; + } } for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); - outEvents.push(allocator->obtainMotionEntry(now(), - memento.deviceId, memento.source, 0, - AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0, - memento.xPrecision, memento.yPrecision, memento.downTime, - memento.pointerCount, memento.pointerIds, memento.pointerCoords)); + if (shouldCancelEvent(memento.source, options)) { + outEvents.push(allocator->obtainMotionEntry(currentTime, + memento.deviceId, memento.source, 0, + AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0, + memento.xPrecision, memento.yPrecision, memento.downTime, + memento.pointerCount, memento.pointerIds, memento.pointerCoords)); + mMotionMementos.removeAt(i); + } else { + i += 1; + } } } void InputDispatcher::InputState::clear() { mKeyMementos.clear(); mMotionMementos.clear(); - mIsOutOfSync = false; +} + +void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { + for (size_t i = 0; i < mMotionMementos.size(); i++) { + const MotionMemento& memento = mMotionMementos.itemAt(i); + if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { + for (size_t j = 0; j < other.mMotionMementos.size(); ) { + const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j); + if (memento.deviceId == otherMemento.deviceId + && memento.source == otherMemento.source) { + other.mMotionMementos.removeAt(j); + } else { + j += 1; + } + } + other.mMotionMementos.push(memento); + } + } +} + +bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource, + CancelationOptions options) { + switch (options) { + case CANCEL_POINTER_EVENTS: + return eventSource & AINPUT_SOURCE_CLASS_POINTER; + case CANCEL_NON_POINTER_EVENTS: + return !(eventSource & AINPUT_SOURCE_CLASS_POINTER); + default: + return true; + } } diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 7adc764..0560bb8 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -796,10 +796,6 @@ int32_t InputMapper::getMetaState() { return 0; } -bool InputMapper::applyStandardPolicyActions(nsecs_t when, int32_t policyActions) { - return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH; -} - // --- SwitchInputMapper --- @@ -823,11 +819,7 @@ void SwitchInputMapper::process(const RawEvent* rawEvent) { } void SwitchInputMapper::processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) { - uint32_t policyFlags = 0; - int32_t policyActions = getPolicy()->interceptSwitch( - when, switchCode, switchValue, policyFlags); - - applyStandardPolicyActions(when, policyActions); + getDispatcher()->notifySwitch(when, switchCode, switchValue, 0); } int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { @@ -983,29 +975,9 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, getContext()->updateGlobalMetaState(); } - applyPolicyAndDispatch(when, policyFlags, down, keyCode, scanCode, newMetaState, downTime); -} - -void KeyboardInputMapper::applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, bool down, - int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) { - int32_t policyActions = getPolicy()->interceptKey(when, - getDeviceId(), down, keyCode, scanCode, policyFlags); - - if (! applyStandardPolicyActions(when, policyActions)) { - return; // event dropped - } - - int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP; - int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM; - if (policyFlags & POLICY_FLAG_WOKE_HERE) { - keyEventFlags |= AKEY_EVENT_FLAG_WOKE_HERE; - } - if (policyFlags & POLICY_FLAG_VIRTUAL) { - keyEventFlags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; - } - getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, - keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); + down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); } ssize_t KeyboardInputMapper::findKeyDownLocked(int32_t scanCode) { @@ -1215,26 +1187,13 @@ void TrackballInputMapper::sync(nsecs_t when) { } } // release lock - applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime); - - mAccumulator.clear(); -} - -void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction, - PointerCoords* pointerCoords, nsecs_t downTime) { - uint32_t policyFlags = 0; - int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags); - - if (! applyStandardPolicyActions(when, policyActions)) { - return; // event dropped - } - int32_t metaState = mContext->getGlobalMetaState(); int32_t pointerId = 0; - - getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags, + getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, 0, motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, - 1, & pointerId, pointerCoords, mXPrecision, mYPrecision, downTime); + 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); + + mAccumulator.clear(); } int32_t TrackballInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { @@ -2012,15 +1971,7 @@ void TouchInputMapper::reset() { } void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { - // Apply generic policy actions. - uint32_t policyFlags = 0; - int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags); - - if (! applyStandardPolicyActions(when, policyActions)) { - mLastTouch.clear(); - return; // event dropped - } // Preprocess pointer data. @@ -2160,24 +2111,11 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( } // release lock // Dispatch virtual key. - applyPolicyAndDispatchVirtualKey(when, policyFlags, keyEventAction, keyEventFlags, - keyCode, scanCode, downTime); - return touchResult; -} - -void TouchInputMapper::applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags, - int32_t keyCode, int32_t scanCode, nsecs_t downTime) { int32_t metaState = mContext->getGlobalMetaState(); - policyFlags |= POLICY_FLAG_VIRTUAL; - int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(), - keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags); - - if (applyStandardPolicyActions(when, policyActions)) { - getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, - keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); - } + getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, + keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); + return touchResult; } void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp index 84a3e2c..f74f395 100644 --- a/media/mtp/MtpServer.cpp +++ b/media/mtp/MtpServer.cpp @@ -163,6 +163,7 @@ void MtpServer::run() { mData.setOperationCode(operation); mData.setTransactionID(transaction); LOGV("sending data:"); + mData.dump(); ret = mData.write(fd); if (ret < 0) { LOGE("request write returned %d, errno: %d", ret, errno); @@ -177,6 +178,7 @@ void MtpServer::run() { mResponse.setTransactionID(transaction); LOGV("sending response %04X", mResponse.getResponseCode()); ret = mResponse.write(fd); + mResponse.dump(); if (ret < 0) { LOGE("request write returned %d, errno: %d", ret, errno); if (errno == ECANCELED) { @@ -546,7 +548,7 @@ MtpResponseCode MtpServer::doGetObject() { // send data header mData.setOperationCode(mRequest.getOperationCode()); mData.setTransactionID(mRequest.getTransactionID()); - mData.writeDataHeader(mFD, fileLength); + mData.writeDataHeader(mFD, fileLength + MTP_CONTAINER_HEADER_SIZE); // then transfer the file int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 68e0e32..449bd4c 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1123,6 +1123,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags, int keyCode, int metaState, int repeatCount, int policyFlags) { + if ((policyFlags & WindowManagerPolicy.FLAG_TRUSTED) == 0) { + return false; + } + final boolean keyguardOn = keyguardOn(); final boolean down = (action == KeyEvent.ACTION_DOWN); final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0); @@ -1149,7 +1153,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!down) { mHomePressed = false; - if (! canceled) { + if (!canceled) { // If an incoming call is ringing, HOME is totally disabled. // (The user is already on the InCallScreen at this point, // and his ONLY options are to answer or reject the call.) @@ -1831,7 +1835,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, int policyFlags, boolean isScreenOn) { int result = ACTION_PASS_TO_USER; - + if ((policyFlags & WindowManagerPolicy.FLAG_TRUSTED) == 0) { + return result; + } + + if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) { + performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); + } + final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; diff --git a/preloaded-classes b/preloaded-classes index 3317286..ee82a2c 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -626,7 +626,6 @@ com.android.internal.app.ChooserActivity com.android.internal.app.ResolverActivity com.android.internal.app.ResolverActivity$ResolveListAdapter com.android.internal.appwidget.IAppWidgetService$Stub -com.android.internal.content.SyncStateContentProviderHelper com.android.internal.graphics.NativeUtils com.android.internal.location.DummyLocationProvider com.android.internal.logging.AndroidHandler diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 808c679..d09dfff 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -320,6 +320,7 @@ CameraService::Client::Client(const sp<CameraService>& cameraService, // Callback is disabled by default mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; mOrientation = 0; + mPreviewWindowFlag = 0; mOrientationChanged = false; mPlayShutterSound = true; cameraService->setCameraBusy(cameraId); @@ -508,6 +509,8 @@ status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) { if (mUseOverlay) { result = setOverlay(); } else if (mPreviewWindow != 0) { + native_window_set_buffers_transform(mPreviewWindow.get(), + mPreviewWindowFlag); result = mHardware->setPreviewWindow(mPreviewWindow); } } @@ -633,7 +636,10 @@ status_t CameraService::Client::startPreviewMode() { if (result != NO_ERROR) return result; result = mHardware->startPreview(); } else { - // XXX: Set the orientation of the ANativeWindow. + if (mPreviewWindow != 0) { + native_window_set_buffers_transform(mPreviewWindow.get(), + mPreviewWindowFlag); + } mHardware->setPreviewWindow(mPreviewWindow); result = mHardware->startPreview(); } @@ -818,15 +824,19 @@ status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t a switch (arg1) { case 0: orientation = ISurface::BufferHeap::ROT_0; + mPreviewWindowFlag = 0; break; case 90: orientation = ISurface::BufferHeap::ROT_90; + mPreviewWindowFlag = NATIVE_WINDOW_TRANSFORM_ROT_90; break; case 180: orientation = ISurface::BufferHeap::ROT_180; + mPreviewWindowFlag = NATIVE_WINDOW_TRANSFORM_ROT_180; break; case 270: orientation = ISurface::BufferHeap::ROT_270; + mPreviewWindowFlag = NATIVE_WINDOW_TRANSFORM_ROT_270; break; default: return BAD_VALUE; diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index d57364a..c8e0c88 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -166,6 +166,7 @@ private: sp<CameraService> mCameraService; // immutable after constructor sp<ICameraClient> mCameraClient; int mCameraId; // immutable after constructor + int mCameraFacing; // immutable after constructor pid_t mClientPid; sp<CameraHardwareInterface> mHardware; // cleared after disconnect() bool mUseOverlay; // immutable after constructor @@ -176,6 +177,7 @@ private: int mOrientation; // Current display orientation // True if display orientation has been changed. This is only used in overlay. int mOrientationChanged; + int mPreviewWindowFlag; bool mPlayShutterSound; // Ensures atomicity among the public methods diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index 4e2f1e3..4931cc7 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -124,6 +124,14 @@ class AlarmManagerService extends IAlarmManager.Stub { public AlarmManagerService(Context context) { mContext = context; mDescriptor = init(); + + // We have to set current TimeZone info to kernel + // because kernel doesn't keep this after reboot + String tz = SystemProperties.get(TIMEZONE_PROPERTY); + if (tz != null) { + setTimeZone(tz); + } + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index fe306b3..cb4071a 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -49,6 +49,8 @@ import java.util.Properties; public class InputManager { static final String TAG = "InputManager"; + private static final boolean DEBUG = false; + private final Callbacks mCallbacks; private final Context mContext; private final WindowManagerService mWindowManagerService; @@ -131,7 +133,9 @@ public class InputManager { throw new IllegalArgumentException("Invalid display id or dimensions."); } - Slog.i(TAG, "Setting display #" + displayId + " size to " + width + "x" + height); + if (DEBUG) { + Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height); + } nativeSetDisplaySize(displayId, width, height); } @@ -140,7 +144,9 @@ public class InputManager { throw new IllegalArgumentException("Invalid rotation."); } - Slog.i(TAG, "Setting display #" + displayId + " orientation to " + rotation); + if (DEBUG) { + Slog.d(TAG, "Setting display #" + displayId + " orientation to " + rotation); + } nativeSetDisplayOrientation(displayId, rotation); } @@ -378,11 +384,6 @@ public class InputManager { private static final String CALIBRATION_DIR_PATH = "usr/idc/"; @SuppressWarnings("unused") - public void virtualKeyDownFeedback() { - mWindowManagerService.mInputMonitor.virtualKeyDownFeedback(); - } - - @SuppressWarnings("unused") public void notifyConfigurationChanged(long whenNanos) { mWindowManagerService.sendNewConfiguration(); } diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 59f7434..8be980f 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -804,7 +804,9 @@ public class WindowManagerService extends IWindowManager.Stub // stop intercepting input mDragState.unregister(); - mInputMonitor.updateInputWindowsLw(); + synchronized (mWindowMap) { + mInputMonitor.updateInputWindowsLw(); + } // free our resources and drop all the object references mDragState.reset(); @@ -5670,13 +5672,6 @@ public class WindowManagerService extends IWindowManager.Stub mTempInputWindows.clear(); } - /* Provides feedback for a virtual key down. */ - public void virtualKeyDownFeedback() { - synchronized (mWindowMap) { - mPolicy.performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); - } - } - /* Notifies that the lid switch changed state. */ public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen); @@ -8128,7 +8123,8 @@ public class WindowManagerService extends IWindowManager.Stub WindowState win = allAppWindows.get(i); if (win == startingWindow || win.mAppFreezing || win.mViewVisibility != View.VISIBLE - || win.mAttrs.type == TYPE_APPLICATION_STARTING) { + || win.mAttrs.type == TYPE_APPLICATION_STARTING + || win.mDestroying) { continue; } if (DEBUG_VISIBILITY) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 3084c16..83351bc 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -6886,6 +6886,9 @@ public final class ActivityManagerService extends ActivityManagerNative sb.append("Subject: ").append(subject).append("\n"); } sb.append("Build: ").append(Build.FINGERPRINT).append("\n"); + if (Debug.isDebuggerConnected()) { + sb.append("Debugger: Connected\n"); + } sb.append("\n"); // Do the rest in a worker thread to avoid blocking the caller on I/O diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp index 8e7cadc..397a84a 100644 --- a/services/jni/com_android_server_BatteryService.cpp +++ b/services/jni/com_android_server_BatteryService.cpp @@ -67,6 +67,7 @@ struct BatteryManagerConstants { jint healthDead; jint healthOverVoltage; jint healthUnspecifiedFailure; + jint healthCold; }; static BatteryManagerConstants gConstants; @@ -104,6 +105,7 @@ static jint getBatteryStatus(const char* status) static jint getBatteryHealth(const char* status) { switch (status[0]) { + case 'C': return gConstants.healthCold; // Cold case 'D': return gConstants.healthDead; // Dead case 'G': return gConstants.healthGood; // Good case 'O': { @@ -390,6 +392,9 @@ int register_android_server_BatteryService(JNIEnv* env) gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I")); + gConstants.healthCold = env->GetStaticIntField(clazz, + env->GetStaticFieldID(clazz, "BATTERY_HEALTH_COLD", "I")); + return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods)); } diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 4f1fab7..e15e8d8 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -50,7 +50,6 @@ static struct { jmethodID notifyLidSwitchChanged; jmethodID notifyInputChannelBroken; jmethodID notifyANR; - jmethodID virtualKeyDownFeedback; jmethodID interceptKeyBeforeQueueing; jmethodID interceptKeyBeforeDispatching; jmethodID checkInjectEventsPermission; @@ -182,11 +181,6 @@ public: virtual bool getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation); - virtual int32_t interceptKey(nsecs_t when, int32_t deviceId, - bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags); - virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, - uint32_t& policyFlags); - virtual int32_t interceptGeneric(nsecs_t when, uint32_t& policyFlags); virtual bool filterTouchEvents(); virtual bool filterJumpyTouchEvents(); virtual void getVirtualKeyDefinitions(const String8& deviceName, @@ -197,6 +191,8 @@ public: /* --- InputDispatcherPolicyInterface implementation --- */ + virtual void notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, + uint32_t policyFlags); virtual void notifyConfigurationChanged(nsecs_t when); virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, const sp<InputChannel>& inputChannel); @@ -204,6 +200,10 @@ public: virtual nsecs_t getKeyRepeatTimeout(); virtual nsecs_t getKeyRepeatDelay(); virtual int32_t getMaxEventsPerSecond(); + virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId, + int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode, + uint32_t& policyFlags); + virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags); virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, const KeyEvent* keyEvent, uint32_t policyFlags); virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType); @@ -254,7 +254,6 @@ private: static bool populateWindow(JNIEnv* env, jobject windowObj, InputWindow& outWindow); - static bool isPolicyKey(int32_t keyCode, bool isScreenOn); static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName); static inline JNIEnv* jniEnv() { @@ -290,37 +289,6 @@ void NativeInputManager::dump(String8& dump) { dump.append("\n"); } -bool NativeInputManager::isPolicyKey(int32_t keyCode, bool isScreenOn) { - // Special keys that the WindowManagerPolicy might care about. - switch (keyCode) { - case AKEYCODE_VOLUME_UP: - case AKEYCODE_VOLUME_DOWN: - case AKEYCODE_ENDCALL: - case AKEYCODE_POWER: - case AKEYCODE_CALL: - case AKEYCODE_HOME: - case AKEYCODE_MENU: - case AKEYCODE_SEARCH: - // media keys - case AKEYCODE_HEADSETHOOK: - case AKEYCODE_MEDIA_PLAY_PAUSE: - case AKEYCODE_MEDIA_STOP: - case AKEYCODE_MEDIA_NEXT: - case AKEYCODE_MEDIA_PREVIOUS: - case AKEYCODE_MEDIA_REWIND: - case AKEYCODE_MEDIA_FAST_FORWARD: - // The policy always cares about these keys. - return true; - default: - // We need to pass all keys to the policy in the following cases: - // - screen is off - // - keyguard is visible - // - policy is performing key chording - //return ! isScreenOn || keyguardVisible || chording; - return true; // XXX stubbed out for now - } -} - bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { if (env->ExceptionCheck()) { LOGE("An exception was thrown by callback '%s'.", methodName); @@ -453,115 +421,6 @@ bool NativeInputManager::getDisplayInfo(int32_t displayId, return result; } -bool NativeInputManager::isScreenOn() { - return android_server_PowerManagerService_isScreenOn(); -} - -bool NativeInputManager::isScreenBright() { - return android_server_PowerManagerService_isScreenBright(); -} - -int32_t NativeInputManager::interceptKey(nsecs_t when, - int32_t deviceId, bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) { -#if DEBUG_INPUT_READER_POLICY - LOGD("interceptKey - when=%lld, deviceId=%d, down=%d, keyCode=%d, scanCode=%d, " - "policyFlags=0x%x", - when, deviceId, down, keyCode, scanCode, policyFlags); -#endif - - if (down && (policyFlags & POLICY_FLAG_VIRTUAL)) { - JNIEnv* env = jniEnv(); - env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback); - checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback"); - } - - const int32_t WM_ACTION_PASS_TO_USER = 1; - const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2; - const int32_t WM_ACTION_GO_TO_SLEEP = 4; - - bool isScreenOn = this->isScreenOn(); - bool isScreenBright = this->isScreenBright(); - - jint wmActions = 0; - if (isPolicyKey(keyCode, isScreenOn)) { - JNIEnv* env = jniEnv(); - - wmActions = env->CallIntMethod(mCallbacksObj, - gCallbacksClassInfo.interceptKeyBeforeQueueing, - when, keyCode, down, policyFlags, isScreenOn); - if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) { - wmActions = 0; - } - } else { - wmActions = WM_ACTION_PASS_TO_USER; - } - - int32_t actions = InputReaderPolicyInterface::ACTION_NONE; - if (! isScreenOn) { - // Key presses and releases wake the device. - policyFlags |= POLICY_FLAG_WOKE_HERE; - } - - if (! isScreenBright) { - // Key presses and releases brighten the screen if dimmed. - policyFlags |= POLICY_FLAG_BRIGHT_HERE; - } - - if (wmActions & WM_ACTION_GO_TO_SLEEP) { - android_server_PowerManagerService_goToSleep(when); - } - - if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) { - android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT); - } - - if (wmActions & WM_ACTION_PASS_TO_USER) { - actions |= InputReaderPolicyInterface::ACTION_DISPATCH; - } - - return actions; -} - -int32_t NativeInputManager::interceptGeneric(nsecs_t when, uint32_t& policyFlags) { -#if DEBUG_INPUT_READER_POLICY - LOGD("interceptGeneric - when=%lld, policyFlags=0x%x", when, policyFlags); -#endif - - int32_t actions = InputReaderPolicyInterface::ACTION_NONE; - if (isScreenOn()) { - // Only dispatch events when the device is awake. - // Do not wake the device. - actions |= InputReaderPolicyInterface::ACTION_DISPATCH; - - if (! isScreenBright()) { - // Brighten the screen if dimmed. - policyFlags |= POLICY_FLAG_BRIGHT_HERE; - } - } - - return actions; -} - -int32_t NativeInputManager::interceptSwitch(nsecs_t when, int32_t switchCode, - int32_t switchValue, uint32_t& policyFlags) { -#if DEBUG_INPUT_READER_POLICY - LOGD("interceptSwitch - when=%lld, switchCode=%d, switchValue=%d, policyFlags=0x%x", - when, switchCode, switchValue, policyFlags); -#endif - - JNIEnv* env = jniEnv(); - - switch (switchCode) { - case SW_LID: - env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyLidSwitchChanged, - when, switchValue == 0); - checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged"); - break; - } - - return InputReaderPolicyInterface::ACTION_NONE; -} - bool NativeInputManager::filterTouchEvents() { if (mFilterTouchEvents < 0) { JNIEnv* env = jniEnv(); @@ -691,6 +550,24 @@ void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDevi } } +void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode, + int32_t switchValue, uint32_t policyFlags) { +#if DEBUG_INPUT_DISPATCHER_POLICY + LOGD("notifySwitch - when=%lld, switchCode=%d, switchValue=%d, policyFlags=0x%x", + when, switchCode, switchValue, policyFlags); +#endif + + JNIEnv* env = jniEnv(); + + switch (switchCode) { + case SW_LID: + env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyLidSwitchChanged, + when, switchValue == 0); + checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged"); + break; + } +} + void NativeInputManager::notifyConfigurationChanged(nsecs_t when) { #if DEBUG_INPUT_DISPATCHER_POLICY LOGD("notifyConfigurationChanged - when=%lld", when); @@ -943,13 +820,88 @@ void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) { mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen); } -bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, - const KeyEvent* keyEvent, uint32_t policyFlags) { +bool NativeInputManager::isScreenOn() { + return android_server_PowerManagerService_isScreenOn(); +} + +bool NativeInputManager::isScreenBright() { + return android_server_PowerManagerService_isScreenBright(); +} + +void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when, + int32_t deviceId, int32_t action, int32_t &flags, + int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) { +#if DEBUG_INPUT_DISPATCHER_POLICY + LOGD("interceptKeyBeforeQueueing - when=%lld, deviceId=%d, action=%d, flags=%d, " + "keyCode=%d, scanCode=%d, policyFlags=0x%x", + when, deviceId, action, flags, keyCode, scanCode, policyFlags); +#endif + + if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) { + policyFlags |= POLICY_FLAG_VIRTUAL; + flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; + } + + const int32_t WM_ACTION_PASS_TO_USER = 1; + const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2; + const int32_t WM_ACTION_GO_TO_SLEEP = 4; + bool isScreenOn = this->isScreenOn(); - if (! isPolicyKey(keyEvent->getKeyCode(), isScreenOn)) { - return false; + bool isScreenBright = this->isScreenBright(); + + JNIEnv* env = jniEnv(); + jint wmActions = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.interceptKeyBeforeQueueing, + when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn); + if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) { + wmActions = 0; + } + + if (policyFlags & POLICY_FLAG_TRUSTED) { + if (! isScreenOn) { + // Key presses and releases wake the device. + policyFlags |= POLICY_FLAG_WOKE_HERE; + flags |= AKEY_EVENT_FLAG_WOKE_HERE; + } + + if (! isScreenBright) { + // Key presses and releases brighten the screen if dimmed. + policyFlags |= POLICY_FLAG_BRIGHT_HERE; + } + + if (wmActions & WM_ACTION_GO_TO_SLEEP) { + android_server_PowerManagerService_goToSleep(when); + } + + if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) { + android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT); + } + } + + if (wmActions & WM_ACTION_PASS_TO_USER) { + policyFlags |= POLICY_FLAG_PASS_TO_USER; } +} +void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { +#if DEBUG_INPUT_DISPATCHER_POLICY + LOGD("interceptGenericBeforeQueueing - when=%lld, policyFlags=0x%x", when, policyFlags); +#endif + + if (isScreenOn()) { + // Only dispatch events when the device is awake. + // Do not wake the device. + policyFlags |= POLICY_FLAG_PASS_TO_USER; + + if ((policyFlags & POLICY_FLAG_TRUSTED) && !isScreenBright()) { + // Brighten the screen if dimmed. + policyFlags |= POLICY_FLAG_BRIGHT_HERE; + } + } +} + +bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, + const KeyEvent* keyEvent, uint32_t policyFlags) { JNIEnv* env = jniEnv(); // Note: inputChannel may be null. @@ -1281,7 +1233,6 @@ static void android_server_InputManager_nativeGetInputConfiguration(JNIEnv* env, static jboolean android_server_InputManager_nativeTransferTouchFocus(JNIEnv* env, jclass clazz, jobject fromChannelObj, jobject toChannelObj) { if (checkInputManagerUnitialized(env)) { - LOGD("input manager uninitialized; bailing"); return false; } @@ -1291,7 +1242,6 @@ static jboolean android_server_InputManager_nativeTransferTouchFocus(JNIEnv* env android_view_InputChannel_getInputChannel(env, toChannelObj); if (fromChannel == NULL || toChannel == NULL) { - LOGD("bailing because from=%p to=%p", fromChannel, toChannel); return false; } @@ -1387,9 +1337,6 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz, "notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J"); - GET_METHOD_ID(gCallbacksClassInfo.virtualKeyDownFeedback, gCallbacksClassInfo.clazz, - "virtualKeyDownFeedback", "()V"); - GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz, "interceptKeyBeforeQueueing", "(JIZIZ)I"); diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp index b312fb1..bd722d7 100755 --- a/services/jni/com_android_server_location_GpsLocationProvider.cpp +++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp @@ -238,7 +238,11 @@ static const GpsInterface* get_gps_interface() { return interface; } -static const GpsInterface* GetGpsInterface() { +static const GpsInterface* GetGpsInterface(JNIEnv* env, jobject obj) { + // this must be set before calling into the HAL library + if (!mCallbacksObj) + mCallbacksObj = env->NewGlobalRef(obj); + if (!sGpsInterface) { sGpsInterface = get_gps_interface(); if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) { @@ -249,9 +253,9 @@ static const GpsInterface* GetGpsInterface() { return sGpsInterface; } -static const AGpsInterface* GetAGpsInterface() +static const AGpsInterface* GetAGpsInterface(JNIEnv* env, jobject obj) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (!interface) return NULL; @@ -263,9 +267,9 @@ static const AGpsInterface* GetAGpsInterface() return sAGpsInterface; } -static const GpsNiInterface* GetNiInterface() +static const GpsNiInterface* GetNiInterface(JNIEnv* env, jobject obj) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (!interface) return NULL; @@ -277,9 +281,9 @@ static const GpsNiInterface* GetNiInterface() return sGpsNiInterface; } -static const AGpsRilInterface* GetAGpsRilInterface() +static const AGpsRilInterface* GetAGpsRilInterface(JNIEnv* env, jobject obj) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (!interface) return NULL; @@ -310,11 +314,7 @@ static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, j static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj) { - // this must be set before calling into the HAL library - if (!mCallbacksObj) - mCallbacksObj = env->NewGlobalRef(obj); - - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (!interface) return false; @@ -326,7 +326,7 @@ static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject o static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (interface) interface->cleanup(); } @@ -334,7 +334,7 @@ static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject ob static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (interface) return (interface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy, preferred_time) == 0); @@ -344,7 +344,7 @@ static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* e static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (interface) return (interface->start() == 0); else @@ -353,7 +353,7 @@ static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (interface) return (interface->stop() == 0); else @@ -362,7 +362,7 @@ static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject o static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (interface) interface->delete_aiding_data(flags); } @@ -402,7 +402,7 @@ static void android_location_GpsLocationProvider_agps_set_reference_location_cel jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid) { AGpsRefLocation location; - const AGpsRilInterface* interface = GetAGpsRilInterface(); + const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); if (!interface) { LOGE("no AGPS RIL interface in agps_set_reference_location_cellid"); return; @@ -429,7 +429,7 @@ static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* en jobject obj, jbyteArray ni_msg, jint size) { size_t sz; - const AGpsRilInterface* interface = GetAGpsRilInterface(); + const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); if (!interface) { LOGE("no AGPS RIL interface in send_ni_message"); return; @@ -445,7 +445,7 @@ static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* en static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env, jobject obj, jint type, jstring setid_string) { - const AGpsRilInterface* interface = GetAGpsRilInterface(); + const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); if (!interface) { LOGE("no AGPS RIL interface in agps_set_id"); return; @@ -472,7 +472,7 @@ static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time, jlong timeReference, jint uncertainty) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (interface) interface->inject_time(time, timeReference, uncertainty); } @@ -480,7 +480,7 @@ static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobjec static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj, jdouble latitude, jdouble longitude, jfloat accuracy) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (interface) interface->inject_location(latitude, longitude, accuracy); } @@ -488,7 +488,7 @@ static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jo static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj) { if (!sGpsXtraInterface) { - const GpsInterface* interface = GetGpsInterface(); + const GpsInterface* interface = GetGpsInterface(env, obj); if (!interface) return false; sGpsXtraInterface = (const GpsXtraInterface*)interface->get_extension(GPS_XTRA_INTERFACE); @@ -513,7 +513,7 @@ static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, j static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn) { - const AGpsInterface* interface = GetAGpsInterface(); + const AGpsInterface* interface = GetAGpsInterface(env, obj); if (!interface) { LOGE("no AGPS interface in agps_data_conn_open"); return; @@ -529,7 +529,7 @@ static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj) { - const AGpsInterface* interface = GetAGpsInterface(); + const AGpsInterface* interface = GetAGpsInterface(env, obj); if (!interface) { LOGE("no AGPS interface in agps_data_conn_open"); return; @@ -539,7 +539,7 @@ static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* e static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj) { - const AGpsInterface* interface = GetAGpsInterface(); + const AGpsInterface* interface = GetAGpsInterface(env, obj); if (!interface) { LOGE("no AGPS interface in agps_data_conn_open"); return; @@ -550,7 +550,7 @@ static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* e static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj, jint type, jstring hostname, jint port) { - const AGpsInterface* interface = GetAGpsInterface(); + const AGpsInterface* interface = GetAGpsInterface(env, obj); if (!interface) { LOGE("no AGPS interface in agps_data_conn_open"); return; @@ -563,7 +563,7 @@ static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jo static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj, jint notifId, jint response) { - const GpsNiInterface* interface = GetNiInterface(); + const GpsNiInterface* interface = GetNiInterface(env, obj); if (!interface) { LOGE("no NI interface in send_ni_response"); return; diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index e37733c..893ae88 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -1823,12 +1823,19 @@ public class PhoneNumberUtils } /** + * Determines if the specified number is actually a URI + * (i.e. a SIP address) rather than a regular PSTN phone number, + * based on whether or not the number contains an "@" character. + * * @hide * @param number * @return true if number contains @ */ public static boolean isUriNumber(String number) { - return number != null && number.contains("@"); + // Note we allow either "@" or "%40" to indicate a URI, in case + // the passed-in string is URI-escaped. (Neither "@" nor "%40" + // will ever be found in a legal PSTN number.) + return number != null && (number.contains("@") || number.contains("%40")); } /** diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index 8c2280b..35d5564 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -1969,26 +1969,30 @@ public final class RIL extends BaseCommands implements CommandsInterface { sendScreenState(true); } - private void setRadioStateFromRILInt(int state) { - RadioState newState; + private RadioState getRadioStateFromInt(int stateInt) { + RadioState state; /* RIL_RadioState ril.h */ - switch(state) { - case 0: newState = RadioState.RADIO_OFF; break; - case 1: newState = RadioState.RADIO_UNAVAILABLE; break; - case 2: newState = RadioState.SIM_NOT_READY; break; - case 3: newState = RadioState.SIM_LOCKED_OR_ABSENT; break; - case 4: newState = RadioState.SIM_READY; break; - case 5: newState = RadioState.RUIM_NOT_READY; break; - case 6: newState = RadioState.RUIM_READY; break; - case 7: newState = RadioState.RUIM_LOCKED_OR_ABSENT; break; - case 8: newState = RadioState.NV_NOT_READY; break; - case 9: newState = RadioState.NV_READY; break; + switch(stateInt) { + case 0: state = RadioState.RADIO_OFF; break; + case 1: state = RadioState.RADIO_UNAVAILABLE; break; + case 2: state = RadioState.SIM_NOT_READY; break; + case 3: state = RadioState.SIM_LOCKED_OR_ABSENT; break; + case 4: state = RadioState.SIM_READY; break; + case 5: state = RadioState.RUIM_NOT_READY; break; + case 6: state = RadioState.RUIM_READY; break; + case 7: state = RadioState.RUIM_LOCKED_OR_ABSENT; break; + case 8: state = RadioState.NV_NOT_READY; break; + case 9: state = RadioState.NV_READY; break; default: throw new RuntimeException( - "Unrecognized RIL_RadioState: " +state); + "Unrecognized RIL_RadioState: " + stateInt); } + return state; + } + + private void switchToRadioState(RadioState newState) { if (mInitialRadioStateChange) { if (newState.isOn()) { @@ -2369,9 +2373,10 @@ public final class RIL extends BaseCommands implements CommandsInterface { switch(response) { case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: /* has bonus radio state int */ - setRadioStateFromRILInt(p.readInt()); + RadioState newState = getRadioStateFromInt(p.readInt()); + if (RILJ_LOGD) unsljLogMore(response, newState.toString()); - if (RILJ_LOGD) unsljLogMore(response, mState.toString()); + switchToRadioState(newState); break; case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: if (RILJ_LOGD) unsljLog(response); diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index 878d30c..a951040 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -18,7 +18,6 @@ package com.android.internal.telephony.sip; import android.content.Context; import android.net.rtp.AudioGroup; -import android.net.rtp.AudioStream; import android.net.sip.SipAudioCall; import android.net.sip.SipErrorCode; import android.net.sip.SipException; @@ -29,11 +28,9 @@ import android.os.AsyncResult; import android.os.Message; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; -import android.text.TextUtils; import android.util.Log; import com.android.internal.telephony.Call; -import com.android.internal.telephony.CallerInfo; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.Connection; import com.android.internal.telephony.Phone; @@ -385,40 +382,6 @@ public class SipPhone extends SipPhoneBase { } } - private CallerInfo createCallerInfo(String number, SipProfile callee) { - SipProfile p = callee; - String name = p.getDisplayName(); - if (TextUtils.isEmpty(name)) name = p.getUserName(); - CallerInfo info = new CallerInfo(); - info.name = name; - info.phoneNumber = number; - if (DEBUG) { - Log.d(LOG_TAG, "create caller info from scratch:"); - Log.d(LOG_TAG, " name: " + info.name); - Log.d(LOG_TAG, " numb: " + info.phoneNumber); - } - return info; - } - - // from contacts - private CallerInfo findCallerInfo(String number) { - CallerInfo info = CallerInfo.getCallerInfo(mContext, number); - if ((info == null) || (info.name == null)) return null; - if (DEBUG) { - Log.d(LOG_TAG, "got caller info from contact:"); - Log.d(LOG_TAG, " name: " + info.name); - Log.d(LOG_TAG, " numb: " + info.phoneNumber); - Log.d(LOG_TAG, " pres: " + info.numberPresentation); - } - return info; - } - - private CallerInfo getCallerInfo(String number, SipProfile callee) { - CallerInfo info = findCallerInfo(number); - if (info == null) info = createCallerInfo(number, callee); - return info; - } - Connection dial(String originalNumber) throws SipException { String calleeSipUri = originalNumber; if (!calleeSipUri.contains("@")) { @@ -427,8 +390,7 @@ public class SipPhone extends SipPhoneBase { try { SipProfile callee = new SipProfile.Builder(calleeSipUri).build(); - CallerInfo info = getCallerInfo(originalNumber, callee); - SipConnection c = new SipConnection(this, callee, info); + SipConnection c = new SipConnection(this, callee); connections.add(c); c.dial(); setState(Call.State.DIALING); @@ -464,10 +426,7 @@ public class SipPhone extends SipPhoneBase { void initIncomingCall(SipAudioCall sipAudioCall, boolean makeCallWait) { SipProfile callee = sipAudioCall.getPeerProfile(); - CallerInfo info = findCallerInfo(getUriString(callee)); - if (info == null) info = findCallerInfo(callee.getUserName()); - if (info == null) info = findCallerInfo(callee.getDisplayName()); - SipConnection c = new SipConnection(this, callee, info); + SipConnection c = new SipConnection(this, callee); connections.add(c); Call.State newState = makeCallWait ? State.WAITING : State.INCOMING; @@ -703,12 +662,10 @@ public class SipPhone extends SipPhoneBase { } }; - public SipConnection(SipCall owner, SipProfile callee, - CallerInfo info) { + public SipConnection(SipCall owner, SipProfile callee) { super(getUriString(callee)); mOwner = owner; mPeer = callee; - setUserData(info); } void initIncomingCall(SipAudioCall sipAudioCall, Call.State newState) { diff --git a/voip/java/com/android/server/sip/SipHelper.java b/voip/java/com/android/server/sip/SipHelper.java index 050eddc..2514262 100644 --- a/voip/java/com/android/server/sip/SipHelper.java +++ b/voip/java/com/android/server/sip/SipHelper.java @@ -238,6 +238,8 @@ class SipHelper { ClientTransaction tid = responseEvent.getClientTransaction(); ClientTransaction ct = authenticationHelper.handleChallenge( responseEvent.getResponse(), tid, mSipProvider, 5); + if (DEBUG) Log.d(TAG, "send request with challenge response: " + + ct.getRequest()); ct.sendRequest(); return ct; } |
