Merge "handleAirplaneModeToggled cleanup" into jb-dev
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 044c0c2..ebe2b98 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -59,9 +59,13 @@
* An accessibility is declared as any other service in an AndroidManifest.xml but it
* must also specify that it handles the "android.accessibilityservice.AccessibilityService"
* {@link android.content.Intent}. Failure to declare this intent will cause the system to
- * ignore the accessibility service. Following is an example declaration:
+ * ignore the accessibility service. Additionally an accessibility service must request
+ * "android.permission.BIND_ACCESSIBILITY_SERVICE" permission to ensure that only the system
+ * can bind to it. Failure to declare this intent will cause the system to ignore the
+ * accessibility service. Following is an example declaration:
* </p>
- * <pre> <service android:name=".MyAccessibilityService">
+ * <pre> <service android:name=".MyAccessibilityService"
+ * android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE>
* <intent-filter>
* <action android:name="android.accessibilityservice.AccessibilityService" />
* </intent-filter>
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 136c68c..291e75e 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -119,8 +119,6 @@
+ savedInstanceState + ")");
}
- setContentView(R.layout.choose_type_and_account);
-
if (savedInstanceState != null) {
mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
mExistingAccounts =
@@ -164,14 +162,29 @@
}
}
- // Read the validAccountTypes, if present, and add them to the setOfAllowableAccountTypes
- Set<String> setOfAllowableAccountTypes = null;
- final String[] validAccountTypes =
+ // An account type is relevant iff it is allowed by the caller and supported by the account
+ // manager.
+ Set<String> setOfRelevantAccountTypes = null;
+ final String[] allowedAccountTypes =
intent.getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
- if (validAccountTypes != null) {
- setOfAllowableAccountTypes = new HashSet<String>(validAccountTypes.length);
- for (String type : validAccountTypes) {
- setOfAllowableAccountTypes.add(type);
+ if (allowedAccountTypes != null) {
+
+ setOfRelevantAccountTypes = new HashSet<String>(allowedAccountTypes.length);
+ Set<String> setOfAllowedAccountTypes = new HashSet<String>(allowedAccountTypes.length);
+ for (String type : allowedAccountTypes) {
+ setOfAllowedAccountTypes.add(type);
+ }
+
+ AuthenticatorDescription[] descs = AccountManager.get(this).getAuthenticatorTypes();
+ Set<String> supportedAccountTypes = new HashSet<String>(descs.length);
+ for (AuthenticatorDescription desc : descs) {
+ supportedAccountTypes.add(desc.type);
+ }
+
+ for (String acctType : setOfAllowedAccountTypes) {
+ if (supportedAccountTypes.contains(acctType)) {
+ setOfRelevantAccountTypes.add(acctType);
+ }
}
}
@@ -185,8 +198,8 @@
&& !setOfAllowableAccounts.contains(account)) {
continue;
}
- if (setOfAllowableAccountTypes != null
- && !setOfAllowableAccountTypes.contains(account.type)) {
+ if (setOfRelevantAccountTypes != null
+ && !setOfRelevantAccountTypes.contains(account.type)) {
continue;
}
mAccountInfos.add(new AccountInfo(account,
@@ -194,30 +207,15 @@
account.equals(selectedAccount)));
}
- // there is more than one allowable account. initialize the list adapter to allow
- // the user to select an account.
- ListView list = (ListView) findViewById(android.R.id.list);
- list.setAdapter(new AccountArrayAdapter(this,
- android.R.layout.simple_list_item_1, mAccountInfos));
- list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
- onListItemClick((ListView)parent, v, position, id);
- }
- });
-
- // set the listener for the addAccount button
- Button addAccountButton = (Button) findViewById(R.id.addAccount);
- addAccountButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(final View v) {
- startChooseAccountTypeActivity();
- }
- });
-
if (mPendingRequest == REQUEST_NULL) {
- // If there are no allowable accounts go directly to add account
- if (shouldSkipToChooseAccountTypeFlow()) {
- startChooseAccountTypeActivity();
+ // If there are no relevant accounts and only one relevant account typoe go directly to
+ // add account. Otherwise let the user choose.
+ if (mAccountInfos.isEmpty()) {
+ if (setOfRelevantAccountTypes.size() == 1) {
+ runAddAccountForAuthenticator(setOfRelevantAccountTypes.iterator().next());
+ } else {
+ startChooseAccountTypeActivity();
+ }
return;
}
@@ -229,6 +227,30 @@
return;
}
}
+
+ setContentView(R.layout.choose_type_and_account);
+
+ // there is more than one allowable account. initialize the list adapter to allow
+ // the user to select an account.
+ ListView list = (ListView) findViewById(android.R.id.list);
+ list.setAdapter(new AccountArrayAdapter(this,
+ android.R.layout.simple_list_item_1, mAccountInfos));
+ list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+ onListItemClick((ListView)parent, v, position, id);
+ }
+ });
+
+ // set the listener for the addAccount button
+ Button addAccountButton = (Button) findViewById(R.id.addAccount);
+ addAccountButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ startChooseAccountTypeActivity();
+ }
+ });
}
@Override
@@ -267,7 +289,7 @@
if (resultCode == RESULT_CANCELED) {
// if cancelling out of addAccount and the original state caused us to skip this,
// finish this activity
- if (shouldSkipToChooseAccountTypeFlow()) {
+ if (mAccountInfos.isEmpty()) {
setResult(Activity.RESULT_CANCELED);
finish();
}
@@ -324,14 +346,6 @@
finish();
}
- /**
- * convenience method to check if we should skip the accounts list display and immediately
- * jump to the flow that asks the user to select from the account type list
- */
- private boolean shouldSkipToChooseAccountTypeFlow() {
- return mAccountInfos.isEmpty();
- }
-
protected void runAddAccountForAuthenticator(String type) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "runAddAccountForAuthenticator: " + type);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0c47069..2eea171 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -907,6 +907,8 @@
* </pre>
*/
public static class Builder {
+ private static final int MAX_ACTION_BUTTONS = 2;
+
private Context mContext;
private long mWhen;
@@ -938,7 +940,7 @@
private ArrayList<String> mKindList = new ArrayList<String>(1);
private Bundle mExtras;
private int mPriority;
- private ArrayList<Action> mActions = new ArrayList<Action>(3);
+ private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
private boolean mUseChronometer;
private Style mStyle;
@@ -1460,7 +1462,7 @@
if (N > 0) {
// Log.d("Notification", "has actions: " + mContentText);
big.setViewVisibility(R.id.actions, View.VISIBLE);
- if (N>3) N=3;
+ if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
big.removeAllViews(R.id.actions);
for (int i=0; i<N; i++) {
final RemoteViews button = generateActionButton(mActions.get(i));
@@ -1500,18 +1502,14 @@
}
private RemoteViews generateActionButton(Action action) {
- RemoteViews button = new RemoteViews(mContext.getPackageName(), R.layout.notification_action);
+ final boolean tombstone = (action.actionIntent == null);
+ RemoteViews button = new RemoteViews(mContext.getPackageName(),
+ tombstone ? R.layout.notification_action_tombstone
+ : R.layout.notification_action);
button.setTextViewCompoundDrawables(R.id.action0, action.icon, 0, 0, 0);
button.setTextViewText(R.id.action0, action.title);
- if (action.actionIntent != null) {
+ if (!tombstone) {
button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
- //button.setBoolean(R.id.action0, "setEnabled", true);
- button.setFloat(R.id.button0, "setAlpha", 1.0f);
- button.setBoolean(R.id.button0, "setClickable", true);
- } else {
- //button.setBoolean(R.id.action0, "setEnabled", false);
- button.setFloat(R.id.button0, "setAlpha", 0.5f);
- button.setBoolean(R.id.button0, "setClickable", false);
}
button.setContentDescription(R.id.action0, action.title);
return button;
@@ -1639,15 +1637,21 @@
if (mBuilder.mSubText == null) {
contentView.setViewVisibility(R.id.line3, View.GONE);
+ } else {
+ contentView.setViewVisibility(R.id.line3, View.VISIBLE);
}
if (mBigContentTitle != null && mBigContentTitle.equals("")) {
contentView.setViewVisibility(R.id.line1, View.GONE);
+ } else {
+ contentView.setViewVisibility(R.id.line1, View.VISIBLE);
}
if (mSummaryText != null && !mSummaryText.equals("")) {
contentView.setViewVisibility(R.id.overflow_title, View.VISIBLE);
contentView.setTextViewText(R.id.overflow_title, mSummaryText);
+ } else {
+ contentView.setViewVisibility(R.id.overflow_title, View.GONE);
}
return contentView;
@@ -1848,6 +1852,11 @@
int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
R.id.inbox_text4};
+ // Make sure all rows are gone in case we reuse a view.
+ for (int rowId : rowIds) {
+ contentView.setViewVisibility(rowId, View.GONE);
+ }
+
int i=0;
while (i < mTexts.size() && i < rowIds.length) {
CharSequence str = mTexts.get(i);
diff --git a/core/java/android/app/TaskStackBuilder.java b/core/java/android/app/TaskStackBuilder.java
index 14c5736..f21b3fd 100644
--- a/core/java/android/app/TaskStackBuilder.java
+++ b/core/java/android/app/TaskStackBuilder.java
@@ -161,18 +161,12 @@
ActivityInfo info = pm.getActivityInfo(
new ComponentName(mSourceContext, sourceActivityClass), 0);
String parentActivity = info.parentActivityName;
- Intent parent = new Intent().setComponent(
- new ComponentName(mSourceContext, parentActivity));
- while (parent != null) {
+ while (parentActivity != null) {
+ Intent parent = new Intent().setComponent(
+ new ComponentName(mSourceContext, parentActivity));
mIntents.add(insertAt, parent);
info = pm.getActivityInfo(parent.getComponent(), 0);
parentActivity = info.parentActivityName;
- if (parentActivity != null) {
- parent = new Intent().setComponent(
- new ComponentName(mSourceContext, parentActivity));
- } else {
- parent = null;
- }
}
} catch (NameNotFoundException e) {
Log.e(TAG, "Bad ComponentName while traversing activity parent metadata");
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 7a8c1fb..3aa5181 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -320,6 +320,10 @@
* It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
* and outside of the handler.
* This method will only work when called from the uid that owns the AppWidget provider.
+ *
+ * <p>
+ * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
+ * fill the screen once, ie. (screen width x screen height x 4) bytes.
*
* @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
* @param views The RemoteViews object to show.
@@ -385,6 +389,10 @@
* and outside of the handler.
* This method will only work when called from the uid that owns the AppWidget provider.
*
+ * <p>
+ * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
+ * fill the screen once, ie. (screen width x screen height x 4) bytes.
+ *
* @param appWidgetId The AppWidget instance for which to set the RemoteViews.
* @param views The RemoteViews object to show.
*/
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index aeb46cf..b8ad818 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1122,9 +1122,9 @@
/** Helper function to compute the angle change between two rotation matrices.
* Given a current rotation matrix (R) and a previous rotation matrix
- * (prevR) computes the rotation around the x,y, and z axes which
+ * (prevR) computes the rotation around the z,x, and y axes which
* transforms prevR to R.
- * outputs a 3 element vector containing the x,y, and z angle
+ * outputs a 3 element vector containing the z,x, and y angle
* change at indexes 0, 1, and 2 respectively.
* <p> Each input matrix is either as a 3x3 or 4x4 row-major matrix
* depending on the length of the passed array:
@@ -1143,14 +1143,13 @@
*</pre>
* @param R current rotation matrix
* @param prevR previous rotation matrix
- * @param angleChange an array of floats in which the angle change is stored
+ * @param angleChange an an array of floats (z, x, and y) in which the angle change is stored
*/
public static void getAngleChange( float[] angleChange, float[] R, float[] prevR) {
float rd1=0,rd4=0, rd6=0,rd7=0, rd8=0;
float ri0=0,ri1=0,ri2=0,ri3=0,ri4=0,ri5=0,ri6=0,ri7=0,ri8=0;
float pri0=0, pri1=0, pri2=0, pri3=0, pri4=0, pri5=0, pri6=0, pri7=0, pri8=0;
- int i, j, k;
if(R.length == 9) {
ri0 = R[0];
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 6a4f1f2..2703f1d 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -261,8 +261,8 @@
* server then the first protocol in the client's list will be selected.
* The order of the client's protocols is otherwise insignificant.
*
- * @param npnProtocols a possibly-empty list of protocol byte arrays. All
- * arrays must be non-empty and of length less than 256.
+ * @param npnProtocols a non-empty list of protocol byte arrays. All arrays
+ * must be non-empty and of length less than 256.
*/
public void setNpnProtocols(byte[][] npnProtocols) {
this.mNpnProtocols = toNpnProtocolsList(npnProtocols);
@@ -273,6 +273,9 @@
* strings.
*/
static byte[] toNpnProtocolsList(byte[]... npnProtocols) {
+ if (npnProtocols.length == 0) {
+ throw new IllegalArgumentException("npnProtocols.length == 0");
+ }
int totalLength = 0;
for (byte[] s : npnProtocols) {
if (s.length == 0 || s.length > 255) {
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index c0240fe..d2050b7 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -43,7 +43,7 @@
public static final int TRACE_FLAGS_START_BIT = 1;
public static final String[] TRACE_TAGS = {
"Graphics", "Input", "View", "WebView", "Window Manager",
- "Activity Manager", "Sync Manager", "Audio"
+ "Activity Manager", "Sync Manager", "Audio", "Video",
};
public static final String PROPERTY_TRACE_TAG_ENABLEFLAGS = "debug.atrace.tags.enableflags";
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index c59ed18..a643c8a 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -261,6 +261,8 @@
@Override
protected void onClick() {
+ if (mDialog != null && mDialog.isShowing()) return;
+
showDialog(null);
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 825f351..183cb88 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -491,14 +491,32 @@
}
}
- private final class FrameDisplayEventReceiver extends DisplayEventReceiver {
+ private final class FrameDisplayEventReceiver extends DisplayEventReceiver
+ implements Runnable {
+ private long mTimestampNanos;
+ private int mFrame;
+
public FrameDisplayEventReceiver(Looper looper) {
super(looper);
}
@Override
public void onVsync(long timestampNanos, int frame) {
- doFrame(timestampNanos, frame);
+ // Post the vsync event to the Handler.
+ // The idea is to prevent incoming vsync events from completely starving
+ // the message queue. If there are no messages in the queue with timestamps
+ // earlier than the frame time, then the vsync event will be processed immediately.
+ // Otherwise, messages that predate the vsync event will be handled first.
+ mTimestampNanos = timestampNanos;
+ mFrame = frame;
+ Message msg = Message.obtain(mHandler, this);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
+ }
+
+ @Override
+ public void run() {
+ doFrame(mTimestampNanos, mFrame);
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a4fcd41..e4062e6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2255,9 +2255,27 @@
* flags, we would like a stable view of the content insets given to
* {@link #fitSystemWindows(Rect)}. This means that the insets seen there
* will always represent the worst case that the application can expect
- * as a continue state. In practice this means with any of system bar,
- * nav bar, and status bar shown, but not the space that would be needed
- * for an input method.
+ * as a continuous state. In the stock Android UI this is the space for
+ * the system bar, nav bar, and status bar, but not more transient elements
+ * such as an input method.
+ *
+ * The stable layout your UI sees is based on the system UI modes you can
+ * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}
+ * then you will get a stable layout for changes of the
+ * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify
+ * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and
+ * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition
+ * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}
+ * with a stable layout. (Note that you should avoid using
+ * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.)
+ *
+ * If you have set the window flag {@ WindowManager.LayoutParams#FLAG_FULLSCREEN}
+ * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}),
+ * then a hidden status bar will be considered a "stable" state for purposes
+ * here. This allows your UI to continually hide the status bar, while still
+ * using the system UI flags to hide the action bar while still retaining
+ * a stable layout. Note that changing the window fullscreen flag will never
+ * provide a stable layout for a clean transition.
*
* <p>If you are using ActionBar in
* overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY
@@ -4776,11 +4794,11 @@
info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
}
- if (isClickable()) {
+ if (isClickable() && isEnabled()) {
info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
}
- if (isLongClickable()) {
+ if (isLongClickable() && isEnabled()) {
info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
}
@@ -6159,7 +6177,8 @@
ViewRootImpl viewRootImpl = getViewRootImpl();
if (viewRootImpl != null) {
View focusHost = viewRootImpl.getAccessibilityFocusedHost();
- if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) {
+ if (focusHost != null && focusHost != this
+ && ViewRootImpl.isViewDescendantOf(focusHost, this)) {
viewRootImpl.setAccessibilityFocusedHost(null);
}
}
@@ -6637,7 +6656,7 @@
private boolean nextAtGranularity(int granularity) {
CharSequence text = getIterableTextForAccessibility();
- if (text != null && text.length() > 0) {
+ if (text == null || text.length() == 0) {
return false;
}
TextSegmentIterator iterator = getIteratorForGranularity(granularity);
@@ -6661,7 +6680,7 @@
private boolean previousAtGranularity(int granularity) {
CharSequence text = getIterableTextForAccessibility();
- if (text != null && text.length() > 0) {
+ if (text == null || text.length() == 0) {
return false;
}
TextSegmentIterator iterator = getIteratorForGranularity(granularity);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index bcd336d..d9e3545 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1076,7 +1076,7 @@
if (baseSize != 0 && desiredWindowWidth > baseSize) {
childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
- host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+ host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
@@ -1087,7 +1087,7 @@
if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
+ baseSize);
childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
- host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+ host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
@@ -1101,7 +1101,7 @@
if (!goodMeasure) {
childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
- host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
windowSizeMayChange = true;
}
@@ -1650,7 +1650,7 @@
+ " coveredInsetsChanged=" + contentInsetsChanged);
// Ask host how big it wants to be
- host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// Implementation of weights from WindowManager.LayoutParams
// We just grow the dimensions as needed and re-measure if
@@ -1676,7 +1676,7 @@
if (DEBUG_LAYOUT) Log.v(TAG,
"And hey let's measure once more: width=" + width
+ " height=" + height);
- host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
layoutRequested = true;
@@ -1688,28 +1688,7 @@
boolean triggerGlobalLayoutListener = didLayout
|| attachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
- mLayoutRequested = false;
- mScrollMayChange = true;
- if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
- TAG, "Laying out " + host + " to (" +
- host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
- long startTime = 0L;
- if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
- startTime = SystemClock.elapsedRealtime();
- }
- host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
-
- if (false && ViewDebug.consistencyCheckEnabled) {
- if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
- throw new IllegalStateException("The view hierarchy is an inconsistent state,"
- + "please refer to the logs with the tag "
- + ViewDebug.CONSISTENCY_LOG_TAG + " for more infomation.");
- }
- }
-
- if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
- EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
- }
+ performLayout();
// By this point all views have been sized and positionned
// We can compute the transparent area
@@ -1867,6 +1846,49 @@
}
}
+ private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
+ try {
+ mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
+
+ private void performLayout() {
+ mLayoutRequested = false;
+ mScrollMayChange = true;
+
+ final View host = mView;
+ if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
+ Log.v(TAG, "Laying out " + host + " to (" +
+ host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
+ }
+
+ final long startTime;
+ if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
+ startTime = SystemClock.elapsedRealtime();
+ }
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
+ try {
+ host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+
+ if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
+ EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
+ }
+
+ if (false && ViewDebug.consistencyCheckEnabled) {
+ if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
+ throw new IllegalStateException("The view hierarchy is an inconsistent state,"
+ + "please refer to the logs with the tag "
+ + ViewDebug.CONSISTENCY_LOG_TAG + " for more infomation.");
+ }
+ }
+ }
+
public void requestTransparentRegion(View child) {
// the test below should not fail unless someone is messing with us
checkThread();
@@ -4447,6 +4469,7 @@
for (int i = 0; i < viewCount; i++) {
mTempViews[i].invalidate();
+ mTempViews[i] = null;
}
for (int i = 0; i < viewRectCount; i++) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d62f513..d94275b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -691,13 +691,6 @@
*/
public static final int FLAG_NEEDS_MENU_KEY = 0x08000000;
- /** Window flag: *sigh* The lock screen wants to continue running its
- * animation while it is fading. A kind-of hack to allow this. Maybe
- * in the future we just make this the default behavior.
- *
- * {@hide} */
- public static final int FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000;
-
/** Window flag: special flag to limit the size of the window to be
* original size ([320x480] x density). Used to create window for applications
* running under compatibility mode.
diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java
index 11bd815..915e2dc 100644
--- a/core/java/android/webkit/AccessibilityInjector.java
+++ b/core/java/android/webkit/AccessibilityInjector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -16,484 +16,335 @@
package android.webkit;
+import android.content.Context;
+import android.os.Vibrator;
import android.provider.Settings;
-import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
-import android.util.Log;
+import android.speech.tts.TextToSpeech;
import android.view.KeyEvent;
-import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.webkit.WebViewCore.EventHub;
-import java.util.ArrayList;
-import java.util.Stack;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
/**
- * This class injects accessibility into WebViews with disabled JavaScript or
- * WebViews with enabled JavaScript but for which we have no accessibility
- * script to inject.
- * </p>
- * Note: To avoid changes in the framework upon changing the available
- * navigation axis, or reordering the navigation axis, or changing
- * the key bindings, or defining sequence of actions to be bound to
- * a given key this class is navigation axis agnostic. It is only
- * aware of one navigation axis which is in fact the default behavior
- * of webViews while using the DPAD/TrackBall.
- * </p>
- * In general a key binding is a mapping from modifiers + key code to
- * a sequence of actions. For more detail how to specify key bindings refer to
- * {@link android.provider.Settings.Secure#ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS}.
- * </p>
- * The possible actions are invocations to
- * {@link #setCurrentAxis(int, boolean, String)}, or
- * {@link #traverseCurrentAxis(int, boolean, String)}
- * {@link #traverseGivenAxis(int, int, boolean, String)}
- * {@link #prefromAxisTransition(int, int, boolean, String)}
- * referred via the values of:
- * {@link #ACTION_SET_CURRENT_AXIS},
- * {@link #ACTION_TRAVERSE_CURRENT_AXIS},
- * {@link #ACTION_TRAVERSE_GIVEN_AXIS},
- * {@link #ACTION_PERFORM_AXIS_TRANSITION},
- * respectively.
- * The arguments for the action invocation are specified as offset
- * hexademical pairs. Note the last argument of the invocation
- * should NOT be specified in the binding as it is provided by
- * this class. For details about the key binding implementation
- * refer to {@link AccessibilityWebContentKeyBinding}.
+ * Handles injecting accessibility JavaScript and related JavaScript -> Java
+ * APIs.
*/
class AccessibilityInjector {
- private static final String LOG_TAG = "AccessibilityInjector";
+ // The WebViewClassic this injector is responsible for managing.
+ private final WebViewClassic mWebViewClassic;
- private static final boolean DEBUG = true;
+ // Cached reference to mWebViewClassic.getContext(), for convenience.
+ private final Context mContext;
- private static final int ACTION_SET_CURRENT_AXIS = 0;
- private static final int ACTION_TRAVERSE_CURRENT_AXIS = 1;
- private static final int ACTION_TRAVERSE_GIVEN_AXIS = 2;
- private static final int ACTION_PERFORM_AXIS_TRANSITION = 3;
- private static final int ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS = 4;
+ // Cached reference to mWebViewClassic.getWebView(), for convenience.
+ private final WebView mWebView;
- // the default WebView behavior abstracted as a navigation axis
- private static final int NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR = 7;
+ // The Java objects that are exposed to JavaScript.
+ private TextToSpeech mTextToSpeech;
- // these are the same for all instances so make them process wide
- private static ArrayList<AccessibilityWebContentKeyBinding> sBindings =
- new ArrayList<AccessibilityWebContentKeyBinding>();
+ // Lazily loaded helper objects.
+ private AccessibilityManager mAccessibilityManager;
+ private AccessibilityInjectorFallback mAccessibilityInjector;
- // handle to the WebViewClassic this injector is associated with.
- private final WebViewClassic mWebView;
+ // Whether the accessibility script has been injected into the current page.
+ private boolean mAccessibilityScriptInjected;
- // events scheduled for sending as soon as we receive the selected text
- private final Stack<AccessibilityEvent> mScheduledEventStack = new Stack<AccessibilityEvent>();
+ // Constants for determining script injection strategy.
+ private static final int ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED = -1;
+ private static final int ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT = 0;
+ @SuppressWarnings("unused")
+ private static final int ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED = 1;
- // the current traversal axis
- private int mCurrentAxis = 2; // sentence
+ // Aliases for Java objects exposed to JavaScript.
+ private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility";
- // we need to consume the up if we have handled the last down
- private boolean mLastDownEventHandled;
-
- // getting two empty selection strings in a row we let the WebView handle the event
- private boolean mIsLastSelectionStringNull;
-
- // keep track of last direction
- private int mLastDirection;
+ // Template for JavaScript that injects a screen-reader.
+ private static final String ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE =
+ "javascript:(function() {" +
+ " var chooser = document.createElement('script');" +
+ " chooser.type = 'text/javascript';" +
+ " chooser.src = '%1s';" +
+ " document.getElementsByTagName('head')[0].appendChild(chooser);" +
+ " })();";
/**
- * Creates a new injector associated with a given {@link WebViewClassic}.
+ * Creates an instance of the AccessibilityInjector based on
+ * {@code webViewClassic}.
*
- * @param webView The associated WebViewClassic.
+ * @param webViewClassic The WebViewClassic that this AccessibilityInjector
+ * manages.
*/
- public AccessibilityInjector(WebViewClassic webView) {
- mWebView = webView;
- ensureWebContentKeyBindings();
+ public AccessibilityInjector(WebViewClassic webViewClassic) {
+ mWebViewClassic = webViewClassic;
+ mWebView = webViewClassic.getWebView();
+ mContext = webViewClassic.getContext();
+ mAccessibilityManager = AccessibilityManager.getInstance(mContext);
}
/**
- * Processes a key down <code>event</code>.
- *
- * @return True if the event was processed.
+ * Attempts to load scripting interfaces for accessibility.
+ * <p>
+ * This should be called when the window is attached.
+ * </p>
*/
- public boolean onKeyEvent(KeyEvent event) {
- // We do not handle ENTER in any circumstances.
- if (isEnterActionKey(event.getKeyCode())) {
+ public void addAccessibilityApisIfNecessary() {
+ if (!isAccessibilityEnabled() || !isJavaScriptEnabled()) {
+ return;
+ }
+
+ addTtsApis();
+ }
+
+ /**
+ * Attempts to unload scripting interfaces for accessibility.
+ * <p>
+ * This should be called when the window is detached.
+ * </p>
+ */
+ public void removeAccessibilityApisIfNecessary() {
+ removeTtsApis();
+ }
+
+ /**
+ * Attempts to handle key events when accessibility is turned on.
+ *
+ * @param event The key event to handle.
+ * @return {@code true} if the event was handled.
+ */
+ public boolean handleKeyEventIfNecessary(KeyEvent event) {
+ if (!isAccessibilityEnabled()) {
+ mAccessibilityScriptInjected = false;
+ toggleFallbackAccessibilityInjector(false);
return false;
}
- if (event.getAction() == KeyEvent.ACTION_UP) {
- return mLastDownEventHandled;
- }
-
- mLastDownEventHandled = false;
-
- AccessibilityWebContentKeyBinding binding = null;
- for (AccessibilityWebContentKeyBinding candidate : sBindings) {
- if (event.getKeyCode() == candidate.getKeyCode()
- && event.hasModifiers(candidate.getModifiers())) {
- binding = candidate;
- break;
+ if (mAccessibilityScriptInjected) {
+ // if an accessibility script is injected we delegate to it the key
+ // handling. this script is a screen reader which is a fully fledged
+ // solution for blind users to navigate in and interact with web
+ // pages.
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ mWebViewClassic.sendBatchableInputMessage(EventHub.KEY_UP, 0, 0, event);
+ } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ mWebViewClassic.sendBatchableInputMessage(EventHub.KEY_DOWN, 0, 0, event);
+ } else {
+ return false;
}
+
+ return true;
}
- if (binding == null) {
+ if (mAccessibilityInjector != null) {
+ // if an accessibility injector is present (no JavaScript enabled or
+ // the site opts out injecting our JavaScript screen reader) we let
+ // it decide whether to act on and consume the event.
+ return mAccessibilityInjector.onKeyEvent(event);
+ }
+
+ return false;
+ }
+
+ /**
+ * Attempts to handle selection change events when accessibility is using a
+ * non-JavaScript method.
+ *
+ * @param selectionString The selection string.
+ */
+ public void handleSelectionChangedIfNecessary(String selectionString) {
+ if (mAccessibilityInjector != null) {
+ mAccessibilityInjector.onSelectionStringChange(selectionString);
+ }
+ }
+
+ /**
+ * Prepares for injecting accessibility scripts into a new page.
+ *
+ * @param url The URL that will be loaded.
+ */
+ public void onPageStarted(String url) {
+ mAccessibilityScriptInjected = false;
+ }
+
+ /**
+ * Attempts to inject the accessibility script using a {@code <script>} tag.
+ * <p>
+ * This should be called after a page has finished loading.
+ * </p>
+ *
+ * @param url The URL that just finished loading.
+ */
+ public void onPageFinished(String url) {
+ if (!isAccessibilityEnabled()) {
+ mAccessibilityScriptInjected = false;
+ toggleFallbackAccessibilityInjector(false);
+ return;
+ }
+
+ if (!shouldInjectJavaScript(url)) {
+ toggleFallbackAccessibilityInjector(true);
+ return;
+ }
+
+ toggleFallbackAccessibilityInjector(false);
+
+ final String injectionUrl = getScreenReaderInjectionUrl();
+ mWebView.loadUrl(injectionUrl);
+
+ mAccessibilityScriptInjected = true;
+ }
+
+ /**
+ * Toggles the non-JavaScript method for handling accessibility.
+ *
+ * @param enabled {@code true} to enable the non-JavaScript method, or
+ * {@code false} to disable it.
+ */
+ private void toggleFallbackAccessibilityInjector(boolean enabled) {
+ if (enabled && (mAccessibilityInjector == null)) {
+ mAccessibilityInjector = new AccessibilityInjectorFallback(mWebViewClassic);
+ } else {
+ mAccessibilityInjector = null;
+ }
+ }
+
+ /**
+ * Determines whether it's okay to inject JavaScript into a given URL.
+ *
+ * @param url The URL to check.
+ * @return {@code true} if JavaScript should be injected, {@code false} if a
+ * non-JavaScript method should be used.
+ */
+ private boolean shouldInjectJavaScript(String url) {
+ // Respect the WebView's JavaScript setting.
+ if (!isJavaScriptEnabled()) {
return false;
}
- for (int i = 0, count = binding.getActionCount(); i < count; i++) {
- int actionCode = binding.getActionCode(i);
- String contentDescription = Integer.toHexString(binding.getAction(i));
- switch (actionCode) {
- case ACTION_SET_CURRENT_AXIS:
- int axis = binding.getFirstArgument(i);
- boolean sendEvent = (binding.getSecondArgument(i) == 1);
- setCurrentAxis(axis, sendEvent, contentDescription);
- mLastDownEventHandled = true;
- break;
- case ACTION_TRAVERSE_CURRENT_AXIS:
- int direction = binding.getFirstArgument(i);
- // on second null selection string in same direction - WebView handles the event
- if (direction == mLastDirection && mIsLastSelectionStringNull) {
- mIsLastSelectionStringNull = false;
- return false;
- }
- mLastDirection = direction;
- sendEvent = (binding.getSecondArgument(i) == 1);
- mLastDownEventHandled = traverseCurrentAxis(direction, sendEvent,
- contentDescription);
- break;
- case ACTION_TRAVERSE_GIVEN_AXIS:
- direction = binding.getFirstArgument(i);
- // on second null selection string in same direction => WebView handle the event
- if (direction == mLastDirection && mIsLastSelectionStringNull) {
- mIsLastSelectionStringNull = false;
- return false;
- }
- mLastDirection = direction;
- axis = binding.getSecondArgument(i);
- sendEvent = (binding.getThirdArgument(i) == 1);
- traverseGivenAxis(direction, axis, sendEvent, contentDescription);
- mLastDownEventHandled = true;
- break;
- case ACTION_PERFORM_AXIS_TRANSITION:
- int fromAxis = binding.getFirstArgument(i);
- int toAxis = binding.getSecondArgument(i);
- sendEvent = (binding.getThirdArgument(i) == 1);
- prefromAxisTransition(fromAxis, toAxis, sendEvent, contentDescription);
- mLastDownEventHandled = true;
- break;
- case ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS:
- // This is a special case since we treat the default WebView navigation
- // behavior as one of the possible navigation axis the user can use.
- // If we are not on the default WebView navigation axis this is NOP.
- if (mCurrentAxis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
- // While WebVew handles navigation we do not get null selection
- // strings so do not check for that here as the cases above.
- mLastDirection = binding.getFirstArgument(i);
- sendEvent = (binding.getSecondArgument(i) == 1);
- traverseGivenAxis(mLastDirection, NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR,
- sendEvent, contentDescription);
- mLastDownEventHandled = false;
- } else {
- mLastDownEventHandled = true;
- }
- break;
- default:
- Log.w(LOG_TAG, "Unknown action code: " + actionCode);
- }
- }
-
- return mLastDownEventHandled;
- }
-
- /**
- * Set the current navigation axis which will be used while
- * calling {@link #traverseCurrentAxis(int, boolean, String)}.
- *
- * @param axis The axis to set.
- * @param sendEvent Whether to send an accessibility event to
- * announce the change.
- */
- private void setCurrentAxis(int axis, boolean sendEvent, String contentDescription) {
- mCurrentAxis = axis;
- if (sendEvent) {
- AccessibilityEvent event = getPartialyPopulatedAccessibilityEvent();
- event.getText().add(String.valueOf(axis));
- event.setContentDescription(contentDescription);
- sendAccessibilityEvent(event);
- }
- }
-
- /**
- * Performs conditional transition one axis to another.
- *
- * @param fromAxis The axis which must be the current for the transition to occur.
- * @param toAxis The axis to which to transition.
- * @param sendEvent Flag if to send an event to announce successful transition.
- * @param contentDescription A description of the performed action.
- */
- private void prefromAxisTransition(int fromAxis, int toAxis, boolean sendEvent,
- String contentDescription) {
- if (mCurrentAxis == fromAxis) {
- setCurrentAxis(toAxis, sendEvent, contentDescription);
- }
- }
-
- /**
- * Traverse the document along the current navigation axis.
- *
- * @param direction The direction of traversal.
- * @param sendEvent Whether to send an accessibility event to
- * announce the change.
- * @param contentDescription A description of the performed action.
- * @see #setCurrentAxis(int, boolean, String)
- */
- private boolean traverseCurrentAxis(int direction, boolean sendEvent,
- String contentDescription) {
- return traverseGivenAxis(direction, mCurrentAxis, sendEvent, contentDescription);
- }
-
- /**
- * Traverse the document along the given navigation axis.
- *
- * @param direction The direction of traversal.
- * @param axis The axis along which to traverse.
- * @param sendEvent Whether to send an accessibility event to
- * announce the change.
- * @param contentDescription A description of the performed action.
- */
- private boolean traverseGivenAxis(int direction, int axis, boolean sendEvent,
- String contentDescription) {
- WebViewCore webViewCore = mWebView.getWebViewCore();
- if (webViewCore == null) {
+ // Allow the page to opt out of Accessibility script injection.
+ if (getAxsUrlParameterValue(url) == ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT) {
return false;
}
- AccessibilityEvent event = null;
- if (sendEvent) {
- event = getPartialyPopulatedAccessibilityEvent();
- // the text will be set upon receiving the selection string
- event.setContentDescription(contentDescription);
- }
- mScheduledEventStack.push(event);
-
- // if the axis is the default let WebView handle the event which will
- // result in cursor ring movement and selection of its content
- if (axis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
+ // The user must explicitly enable Accessibility script injection.
+ if (!isScriptInjectionEnabled()) {
return false;
}
- webViewCore.sendMessage(EventHub.MODIFY_SELECTION, direction, axis);
return true;
}
/**
- * Called when the <code>selectionString</code> has changed.
+ * @return {@code true} if the user has explicitly enabled Accessibility
+ * script injection.
*/
- public void onSelectionStringChange(String selectionString) {
- if (DEBUG) {
- Log.d(LOG_TAG, "Selection string: " + selectionString);
- }
- mIsLastSelectionStringNull = (selectionString == null);
- if (mScheduledEventStack.isEmpty()) {
- return;
- }
- AccessibilityEvent event = mScheduledEventStack.pop();
- if (event != null) {
- event.getText().add(selectionString);
- sendAccessibilityEvent(event);
- }
+ private boolean isScriptInjectionEnabled() {
+ final int injectionSetting = Settings.Secure.getInt(
+ mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0);
+ return (injectionSetting == 1);
}
/**
- * Sends an {@link AccessibilityEvent}.
+ * Attempts to initialize and add interfaces for TTS, if that hasn't already
+ * been done.
+ */
+ private void addTtsApis() {
+ if (mTextToSpeech != null) {
+ return;
+ }
+
+ final String pkgName = mContext.getPackageName();
+
+ mTextToSpeech = new TextToSpeech(mContext, null, null, pkgName + ".**webview**", true);
+ mWebView.addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE);
+ }
+
+ /**
+ * Attempts to shutdown and remove interfaces for TTS, if that hasn't
+ * already been done.
+ */
+ private void removeTtsApis() {
+ if (mTextToSpeech == null) {
+ return;
+ }
+
+ mWebView.removeJavascriptInterface(ALIAS_ACCESSIBILITY_JS_INTERFACE);
+ mTextToSpeech.stop();
+ mTextToSpeech.shutdown();
+ mTextToSpeech = null;
+ }
+
+ /**
+ * Returns the script injection preference requested by the URL, or
+ * {@link #ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED} if the page has no
+ * preference.
*
- * @param event The event to send.
+ * @param url The URL to check.
+ * @return A script injection preference.
*/
- private void sendAccessibilityEvent(AccessibilityEvent event) {
- if (DEBUG) {
- Log.d(LOG_TAG, "Dispatching: " + event);
- }
- // accessibility may be disabled while waiting for the selection string
- AccessibilityManager accessibilityManager =
- AccessibilityManager.getInstance(mWebView.getContext());
- if (accessibilityManager.isEnabled()) {
- accessibilityManager.sendAccessibilityEvent(event);
- }
- }
-
- /**
- * @return An accessibility event whose members are populated except its
- * text and content description.
- */
- private AccessibilityEvent getPartialyPopulatedAccessibilityEvent() {
- AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SELECTED);
- event.setClassName(mWebView.getClass().getName());
- event.setPackageName(mWebView.getContext().getPackageName());
- event.setEnabled(mWebView.getWebView().isEnabled());
- return event;
- }
-
- /**
- * Ensures that the Web content key bindings are loaded.
- */
- private void ensureWebContentKeyBindings() {
- if (sBindings.size() > 0) {
- return;
+ private int getAxsUrlParameterValue(String url) {
+ if (url == null) {
+ return ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED;
}
- String webContentKeyBindingsString = Settings.Secure.getString(
- mWebView.getContext().getContentResolver(),
- Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS);
+ try {
+ final List<NameValuePair> params = URLEncodedUtils.parse(new URI(url), null);
- SimpleStringSplitter semiColonSplitter = new SimpleStringSplitter(';');
- semiColonSplitter.setString(webContentKeyBindingsString);
-
- while (semiColonSplitter.hasNext()) {
- String bindingString = semiColonSplitter.next();
- if (TextUtils.isEmpty(bindingString)) {
- Log.e(LOG_TAG, "Disregarding malformed Web content key binding: "
- + webContentKeyBindingsString);
- continue;
- }
- String[] keyValueArray = bindingString.split("=");
- if (keyValueArray.length != 2) {
- Log.e(LOG_TAG, "Disregarding malformed Web content key binding: " + bindingString);
- continue;
- }
- try {
- long keyCodeAndModifiers = Long.decode(keyValueArray[0].trim());
- String[] actionStrings = keyValueArray[1].split(":");
- int[] actions = new int[actionStrings.length];
- for (int i = 0, count = actions.length; i < count; i++) {
- actions[i] = Integer.decode(actionStrings[i].trim());
+ for (NameValuePair param : params) {
+ if ("axs".equals(param.getName())) {
+ return verifyInjectionValue(param.getValue());
}
- sBindings.add(new AccessibilityWebContentKeyBinding(keyCodeAndModifiers, actions));
- } catch (NumberFormatException nfe) {
- Log.e(LOG_TAG, "Disregarding malformed key binding: " + bindingString);
}
+ } catch (URISyntaxException e) {
+ // Do nothing.
}
+
+ return ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED;
}
- private boolean isEnterActionKey(int keyCode) {
- return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
- || keyCode == KeyEvent.KEYCODE_ENTER
- || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER;
+ private int verifyInjectionValue(String value) {
+ try {
+ final int parsed = Integer.parseInt(value);
+
+ switch (parsed) {
+ case ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT:
+ return ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT;
+ case ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED:
+ return ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED;
+ }
+ } catch (NumberFormatException e) {
+ // Do nothing.
+ }
+
+ return ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED;
}
/**
- * Represents a web content key-binding.
+ * @return The URL for injecting the screen reader.
*/
- private static final class AccessibilityWebContentKeyBinding {
+ private String getScreenReaderInjectionUrl() {
+ final String screenReaderUrl = Settings.Secure.getString(
+ mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL);
+ return String.format(ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE, screenReaderUrl);
+ }
- private static final int MODIFIERS_OFFSET = 32;
- private static final long MODIFIERS_MASK = 0xFFFFFFF00000000L;
+ /**
+ * @return {@code true} if JavaScript is enabled in the {@link WebView}
+ * settings.
+ */
+ private boolean isJavaScriptEnabled() {
+ return mWebView.getSettings().getJavaScriptEnabled();
+ }
- private static final int KEY_CODE_OFFSET = 0;
- private static final long KEY_CODE_MASK = 0x00000000FFFFFFFFL;
-
- private static final int ACTION_OFFSET = 24;
- private static final int ACTION_MASK = 0xFF000000;
-
- private static final int FIRST_ARGUMENT_OFFSET = 16;
- private static final int FIRST_ARGUMENT_MASK = 0x00FF0000;
-
- private static final int SECOND_ARGUMENT_OFFSET = 8;
- private static final int SECOND_ARGUMENT_MASK = 0x0000FF00;
-
- private static final int THIRD_ARGUMENT_OFFSET = 0;
- private static final int THIRD_ARGUMENT_MASK = 0x000000FF;
-
- private final long mKeyCodeAndModifiers;
-
- private final int [] mActionSequence;
-
- /**
- * @return The key code of the binding key.
- */
- public int getKeyCode() {
- return (int) ((mKeyCodeAndModifiers & KEY_CODE_MASK) >> KEY_CODE_OFFSET);
- }
-
- /**
- * @return The meta state of the binding key.
- */
- public int getModifiers() {
- return (int) ((mKeyCodeAndModifiers & MODIFIERS_MASK) >> MODIFIERS_OFFSET);
- }
-
- /**
- * @return The number of actions in the key binding.
- */
- public int getActionCount() {
- return mActionSequence.length;
- }
-
- /**
- * @param index The action for a given action <code>index</code>.
- */
- public int getAction(int index) {
- return mActionSequence[index];
- }
-
- /**
- * @param index The action code for a given action <code>index</code>.
- */
- public int getActionCode(int index) {
- return (mActionSequence[index] & ACTION_MASK) >> ACTION_OFFSET;
- }
-
- /**
- * @param index The first argument for a given action <code>index</code>.
- */
- public int getFirstArgument(int index) {
- return (mActionSequence[index] & FIRST_ARGUMENT_MASK) >> FIRST_ARGUMENT_OFFSET;
- }
-
- /**
- * @param index The second argument for a given action <code>index</code>.
- */
- public int getSecondArgument(int index) {
- return (mActionSequence[index] & SECOND_ARGUMENT_MASK) >> SECOND_ARGUMENT_OFFSET;
- }
-
- /**
- * @param index The third argument for a given action <code>index</code>.
- */
- public int getThirdArgument(int index) {
- return (mActionSequence[index] & THIRD_ARGUMENT_MASK) >> THIRD_ARGUMENT_OFFSET;
- }
-
- /**
- * Creates a new instance.
- * @param keyCodeAndModifiers The key for the binding (key and modifiers).
- * @param actionSequence The sequence of action for the binding.
- */
- public AccessibilityWebContentKeyBinding(long keyCodeAndModifiers, int[] actionSequence) {
- mKeyCodeAndModifiers = keyCodeAndModifiers;
- mActionSequence = actionSequence;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("modifiers: ");
- builder.append(getModifiers());
- builder.append(", keyCode: ");
- builder.append(getKeyCode());
- builder.append(", actions[");
- for (int i = 0, count = getActionCount(); i < count; i++) {
- builder.append("{actionCode");
- builder.append(i);
- builder.append(": ");
- builder.append(getActionCode(i));
- builder.append(", firstArgument: ");
- builder.append(getFirstArgument(i));
- builder.append(", secondArgument: ");
- builder.append(getSecondArgument(i));
- builder.append(", thirdArgument: ");
- builder.append(getThirdArgument(i));
- builder.append("}");
- }
- builder.append("]");
- return builder.toString();
- }
+ /**
+ * @return {@code true} if accessibility is enabled.
+ */
+ private boolean isAccessibilityEnabled() {
+ return mAccessibilityManager.isEnabled();
}
}
diff --git a/core/java/android/webkit/AccessibilityInjectorFallback.java b/core/java/android/webkit/AccessibilityInjectorFallback.java
new file mode 100644
index 0000000..9bf52ca
--- /dev/null
+++ b/core/java/android/webkit/AccessibilityInjectorFallback.java
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.webkit.WebViewCore.EventHub;
+
+import java.util.ArrayList;
+import java.util.Stack;
+
+/**
+ * This class injects accessibility into WebViews with disabled JavaScript or
+ * WebViews with enabled JavaScript but for which we have no accessibility
+ * script to inject.
+ * </p>
+ * Note: To avoid changes in the framework upon changing the available
+ * navigation axis, or reordering the navigation axis, or changing
+ * the key bindings, or defining sequence of actions to be bound to
+ * a given key this class is navigation axis agnostic. It is only
+ * aware of one navigation axis which is in fact the default behavior
+ * of webViews while using the DPAD/TrackBall.
+ * </p>
+ * In general a key binding is a mapping from modifiers + key code to
+ * a sequence of actions. For more detail how to specify key bindings refer to
+ * {@link android.provider.Settings.Secure#ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS}.
+ * </p>
+ * The possible actions are invocations to
+ * {@link #setCurrentAxis(int, boolean, String)}, or
+ * {@link #traverseCurrentAxis(int, boolean, String)}
+ * {@link #traverseGivenAxis(int, int, boolean, String)}
+ * {@link #prefromAxisTransition(int, int, boolean, String)}
+ * referred via the values of:
+ * {@link #ACTION_SET_CURRENT_AXIS},
+ * {@link #ACTION_TRAVERSE_CURRENT_AXIS},
+ * {@link #ACTION_TRAVERSE_GIVEN_AXIS},
+ * {@link #ACTION_PERFORM_AXIS_TRANSITION},
+ * respectively.
+ * The arguments for the action invocation are specified as offset
+ * hexademical pairs. Note the last argument of the invocation
+ * should NOT be specified in the binding as it is provided by
+ * this class. For details about the key binding implementation
+ * refer to {@link AccessibilityWebContentKeyBinding}.
+ */
+class AccessibilityInjectorFallback {
+ private static final String LOG_TAG = "AccessibilityInjector";
+
+ private static final boolean DEBUG = true;
+
+ private static final int ACTION_SET_CURRENT_AXIS = 0;
+ private static final int ACTION_TRAVERSE_CURRENT_AXIS = 1;
+ private static final int ACTION_TRAVERSE_GIVEN_AXIS = 2;
+ private static final int ACTION_PERFORM_AXIS_TRANSITION = 3;
+ private static final int ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS = 4;
+
+ // the default WebView behavior abstracted as a navigation axis
+ private static final int NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR = 7;
+
+ // these are the same for all instances so make them process wide
+ private static ArrayList<AccessibilityWebContentKeyBinding> sBindings =
+ new ArrayList<AccessibilityWebContentKeyBinding>();
+
+ // handle to the WebViewClassic this injector is associated with.
+ private final WebViewClassic mWebView;
+
+ // events scheduled for sending as soon as we receive the selected text
+ private final Stack<AccessibilityEvent> mScheduledEventStack = new Stack<AccessibilityEvent>();
+
+ // the current traversal axis
+ private int mCurrentAxis = 2; // sentence
+
+ // we need to consume the up if we have handled the last down
+ private boolean mLastDownEventHandled;
+
+ // getting two empty selection strings in a row we let the WebView handle the event
+ private boolean mIsLastSelectionStringNull;
+
+ // keep track of last direction
+ private int mLastDirection;
+
+ /**
+ * Creates a new injector associated with a given {@link WebViewClassic}.
+ *
+ * @param webView The associated WebViewClassic.
+ */
+ public AccessibilityInjectorFallback(WebViewClassic webView) {
+ mWebView = webView;
+ ensureWebContentKeyBindings();
+ }
+
+ /**
+ * Processes a key down <code>event</code>.
+ *
+ * @return True if the event was processed.
+ */
+ public boolean onKeyEvent(KeyEvent event) {
+ // We do not handle ENTER in any circumstances.
+ if (isEnterActionKey(event.getKeyCode())) {
+ return false;
+ }
+
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ return mLastDownEventHandled;
+ }
+
+ mLastDownEventHandled = false;
+
+ AccessibilityWebContentKeyBinding binding = null;
+ for (AccessibilityWebContentKeyBinding candidate : sBindings) {
+ if (event.getKeyCode() == candidate.getKeyCode()
+ && event.hasModifiers(candidate.getModifiers())) {
+ binding = candidate;
+ break;
+ }
+ }
+
+ if (binding == null) {
+ return false;
+ }
+
+ for (int i = 0, count = binding.getActionCount(); i < count; i++) {
+ int actionCode = binding.getActionCode(i);
+ String contentDescription = Integer.toHexString(binding.getAction(i));
+ switch (actionCode) {
+ case ACTION_SET_CURRENT_AXIS:
+ int axis = binding.getFirstArgument(i);
+ boolean sendEvent = (binding.getSecondArgument(i) == 1);
+ setCurrentAxis(axis, sendEvent, contentDescription);
+ mLastDownEventHandled = true;
+ break;
+ case ACTION_TRAVERSE_CURRENT_AXIS:
+ int direction = binding.getFirstArgument(i);
+ // on second null selection string in same direction - WebView handles the event
+ if (direction == mLastDirection && mIsLastSelectionStringNull) {
+ mIsLastSelectionStringNull = false;
+ return false;
+ }
+ mLastDirection = direction;
+ sendEvent = (binding.getSecondArgument(i) == 1);
+ mLastDownEventHandled = traverseCurrentAxis(direction, sendEvent,
+ contentDescription);
+ break;
+ case ACTION_TRAVERSE_GIVEN_AXIS:
+ direction = binding.getFirstArgument(i);
+ // on second null selection string in same direction => WebView handle the event
+ if (direction == mLastDirection && mIsLastSelectionStringNull) {
+ mIsLastSelectionStringNull = false;
+ return false;
+ }
+ mLastDirection = direction;
+ axis = binding.getSecondArgument(i);
+ sendEvent = (binding.getThirdArgument(i) == 1);
+ traverseGivenAxis(direction, axis, sendEvent, contentDescription);
+ mLastDownEventHandled = true;
+ break;
+ case ACTION_PERFORM_AXIS_TRANSITION:
+ int fromAxis = binding.getFirstArgument(i);
+ int toAxis = binding.getSecondArgument(i);
+ sendEvent = (binding.getThirdArgument(i) == 1);
+ prefromAxisTransition(fromAxis, toAxis, sendEvent, contentDescription);
+ mLastDownEventHandled = true;
+ break;
+ case ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS:
+ // This is a special case since we treat the default WebView navigation
+ // behavior as one of the possible navigation axis the user can use.
+ // If we are not on the default WebView navigation axis this is NOP.
+ if (mCurrentAxis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
+ // While WebVew handles navigation we do not get null selection
+ // strings so do not check for that here as the cases above.
+ mLastDirection = binding.getFirstArgument(i);
+ sendEvent = (binding.getSecondArgument(i) == 1);
+ traverseGivenAxis(mLastDirection, NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR,
+ sendEvent, contentDescription);
+ mLastDownEventHandled = false;
+ } else {
+ mLastDownEventHandled = true;
+ }
+ break;
+ default:
+ Log.w(LOG_TAG, "Unknown action code: " + actionCode);
+ }
+ }
+
+ return mLastDownEventHandled;
+ }
+
+ /**
+ * Set the current navigation axis which will be used while
+ * calling {@link #traverseCurrentAxis(int, boolean, String)}.
+ *
+ * @param axis The axis to set.
+ * @param sendEvent Whether to send an accessibility event to
+ * announce the change.
+ */
+ private void setCurrentAxis(int axis, boolean sendEvent, String contentDescription) {
+ mCurrentAxis = axis;
+ if (sendEvent) {
+ AccessibilityEvent event = getPartialyPopulatedAccessibilityEvent();
+ event.getText().add(String.valueOf(axis));
+ event.setContentDescription(contentDescription);
+ sendAccessibilityEvent(event);
+ }
+ }
+
+ /**
+ * Performs conditional transition one axis to another.
+ *
+ * @param fromAxis The axis which must be the current for the transition to occur.
+ * @param toAxis The axis to which to transition.
+ * @param sendEvent Flag if to send an event to announce successful transition.
+ * @param contentDescription A description of the performed action.
+ */
+ private void prefromAxisTransition(int fromAxis, int toAxis, boolean sendEvent,
+ String contentDescription) {
+ if (mCurrentAxis == fromAxis) {
+ setCurrentAxis(toAxis, sendEvent, contentDescription);
+ }
+ }
+
+ /**
+ * Traverse the document along the current navigation axis.
+ *
+ * @param direction The direction of traversal.
+ * @param sendEvent Whether to send an accessibility event to
+ * announce the change.
+ * @param contentDescription A description of the performed action.
+ * @see #setCurrentAxis(int, boolean, String)
+ */
+ private boolean traverseCurrentAxis(int direction, boolean sendEvent,
+ String contentDescription) {
+ return traverseGivenAxis(direction, mCurrentAxis, sendEvent, contentDescription);
+ }
+
+ /**
+ * Traverse the document along the given navigation axis.
+ *
+ * @param direction The direction of traversal.
+ * @param axis The axis along which to traverse.
+ * @param sendEvent Whether to send an accessibility event to
+ * announce the change.
+ * @param contentDescription A description of the performed action.
+ */
+ private boolean traverseGivenAxis(int direction, int axis, boolean sendEvent,
+ String contentDescription) {
+ WebViewCore webViewCore = mWebView.getWebViewCore();
+ if (webViewCore == null) {
+ return false;
+ }
+
+ AccessibilityEvent event = null;
+ if (sendEvent) {
+ event = getPartialyPopulatedAccessibilityEvent();
+ // the text will be set upon receiving the selection string
+ event.setContentDescription(contentDescription);
+ }
+ mScheduledEventStack.push(event);
+
+ // if the axis is the default let WebView handle the event which will
+ // result in cursor ring movement and selection of its content
+ if (axis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
+ return false;
+ }
+
+ webViewCore.sendMessage(EventHub.MODIFY_SELECTION, direction, axis);
+ return true;
+ }
+
+ /**
+ * Called when the <code>selectionString</code> has changed.
+ */
+ public void onSelectionStringChange(String selectionString) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Selection string: " + selectionString);
+ }
+ mIsLastSelectionStringNull = (selectionString == null);
+ if (mScheduledEventStack.isEmpty()) {
+ return;
+ }
+ AccessibilityEvent event = mScheduledEventStack.pop();
+ if (event != null) {
+ event.getText().add(selectionString);
+ sendAccessibilityEvent(event);
+ }
+ }
+
+ /**
+ * Sends an {@link AccessibilityEvent}.
+ *
+ * @param event The event to send.
+ */
+ private void sendAccessibilityEvent(AccessibilityEvent event) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Dispatching: " + event);
+ }
+ // accessibility may be disabled while waiting for the selection string
+ AccessibilityManager accessibilityManager =
+ AccessibilityManager.getInstance(mWebView.getContext());
+ if (accessibilityManager.isEnabled()) {
+ accessibilityManager.sendAccessibilityEvent(event);
+ }
+ }
+
+ /**
+ * @return An accessibility event whose members are populated except its
+ * text and content description.
+ */
+ private AccessibilityEvent getPartialyPopulatedAccessibilityEvent() {
+ AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SELECTED);
+ event.setClassName(mWebView.getClass().getName());
+ event.setPackageName(mWebView.getContext().getPackageName());
+ event.setEnabled(mWebView.getWebView().isEnabled());
+ return event;
+ }
+
+ /**
+ * Ensures that the Web content key bindings are loaded.
+ */
+ private void ensureWebContentKeyBindings() {
+ if (sBindings.size() > 0) {
+ return;
+ }
+
+ String webContentKeyBindingsString = Settings.Secure.getString(
+ mWebView.getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS);
+
+ SimpleStringSplitter semiColonSplitter = new SimpleStringSplitter(';');
+ semiColonSplitter.setString(webContentKeyBindingsString);
+
+ while (semiColonSplitter.hasNext()) {
+ String bindingString = semiColonSplitter.next();
+ if (TextUtils.isEmpty(bindingString)) {
+ Log.e(LOG_TAG, "Disregarding malformed Web content key binding: "
+ + webContentKeyBindingsString);
+ continue;
+ }
+ String[] keyValueArray = bindingString.split("=");
+ if (keyValueArray.length != 2) {
+ Log.e(LOG_TAG, "Disregarding malformed Web content key binding: " + bindingString);
+ continue;
+ }
+ try {
+ long keyCodeAndModifiers = Long.decode(keyValueArray[0].trim());
+ String[] actionStrings = keyValueArray[1].split(":");
+ int[] actions = new int[actionStrings.length];
+ for (int i = 0, count = actions.length; i < count; i++) {
+ actions[i] = Integer.decode(actionStrings[i].trim());
+ }
+ sBindings.add(new AccessibilityWebContentKeyBinding(keyCodeAndModifiers, actions));
+ } catch (NumberFormatException nfe) {
+ Log.e(LOG_TAG, "Disregarding malformed key binding: " + bindingString);
+ }
+ }
+ }
+
+ private boolean isEnterActionKey(int keyCode) {
+ return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+ || keyCode == KeyEvent.KEYCODE_ENTER
+ || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER;
+ }
+
+ /**
+ * Represents a web content key-binding.
+ */
+ private static final class AccessibilityWebContentKeyBinding {
+
+ private static final int MODIFIERS_OFFSET = 32;
+ private static final long MODIFIERS_MASK = 0xFFFFFFF00000000L;
+
+ private static final int KEY_CODE_OFFSET = 0;
+ private static final long KEY_CODE_MASK = 0x00000000FFFFFFFFL;
+
+ private static final int ACTION_OFFSET = 24;
+ private static final int ACTION_MASK = 0xFF000000;
+
+ private static final int FIRST_ARGUMENT_OFFSET = 16;
+ private static final int FIRST_ARGUMENT_MASK = 0x00FF0000;
+
+ private static final int SECOND_ARGUMENT_OFFSET = 8;
+ private static final int SECOND_ARGUMENT_MASK = 0x0000FF00;
+
+ private static final int THIRD_ARGUMENT_OFFSET = 0;
+ private static final int THIRD_ARGUMENT_MASK = 0x000000FF;
+
+ private final long mKeyCodeAndModifiers;
+
+ private final int [] mActionSequence;
+
+ /**
+ * @return The key code of the binding key.
+ */
+ public int getKeyCode() {
+ return (int) ((mKeyCodeAndModifiers & KEY_CODE_MASK) >> KEY_CODE_OFFSET);
+ }
+
+ /**
+ * @return The meta state of the binding key.
+ */
+ public int getModifiers() {
+ return (int) ((mKeyCodeAndModifiers & MODIFIERS_MASK) >> MODIFIERS_OFFSET);
+ }
+
+ /**
+ * @return The number of actions in the key binding.
+ */
+ public int getActionCount() {
+ return mActionSequence.length;
+ }
+
+ /**
+ * @param index The action for a given action <code>index</code>.
+ */
+ public int getAction(int index) {
+ return mActionSequence[index];
+ }
+
+ /**
+ * @param index The action code for a given action <code>index</code>.
+ */
+ public int getActionCode(int index) {
+ return (mActionSequence[index] & ACTION_MASK) >> ACTION_OFFSET;
+ }
+
+ /**
+ * @param index The first argument for a given action <code>index</code>.
+ */
+ public int getFirstArgument(int index) {
+ return (mActionSequence[index] & FIRST_ARGUMENT_MASK) >> FIRST_ARGUMENT_OFFSET;
+ }
+
+ /**
+ * @param index The second argument for a given action <code>index</code>.
+ */
+ public int getSecondArgument(int index) {
+ return (mActionSequence[index] & SECOND_ARGUMENT_MASK) >> SECOND_ARGUMENT_OFFSET;
+ }
+
+ /**
+ * @param index The third argument for a given action <code>index</code>.
+ */
+ public int getThirdArgument(int index) {
+ return (mActionSequence[index] & THIRD_ARGUMENT_MASK) >> THIRD_ARGUMENT_OFFSET;
+ }
+
+ /**
+ * Creates a new instance.
+ * @param keyCodeAndModifiers The key for the binding (key and modifiers).
+ * @param actionSequence The sequence of action for the binding.
+ */
+ public AccessibilityWebContentKeyBinding(long keyCodeAndModifiers, int[] actionSequence) {
+ mKeyCodeAndModifiers = keyCodeAndModifiers;
+ mActionSequence = actionSequence;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("modifiers: ");
+ builder.append(getModifiers());
+ builder.append(", keyCode: ");
+ builder.append(getKeyCode());
+ builder.append(", actions[");
+ for (int i = 0, count = getActionCount(); i < count; i++) {
+ builder.append("{actionCode");
+ builder.append(i);
+ builder.append(": ");
+ builder.append(getActionCode(i));
+ builder.append(", firstArgument: ");
+ builder.append(getFirstArgument(i));
+ builder.append(", secondArgument: ");
+ builder.append(getSecondArgument(i));
+ builder.append(", thirdArgument: ");
+ builder.append(getThirdArgument(i));
+ builder.append("}");
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+ }
+}
diff --git a/core/java/android/webkit/WebCoreThreadWatchdog.java b/core/java/android/webkit/WebCoreThreadWatchdog.java
index 655db31..a22e6e8 100644
--- a/core/java/android/webkit/WebCoreThreadWatchdog.java
+++ b/core/java/android/webkit/WebCoreThreadWatchdog.java
@@ -26,6 +26,10 @@
import android.os.Process;
import android.webkit.WebViewCore.EventHub;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
// A Runnable that will monitor if the WebCore thread is still
// processing messages by pinging it every so often. It is safe
// to call the public methods of this class from any thread.
@@ -51,25 +55,31 @@
// After the first timeout, use a shorter period before re-prompting the user.
private static final int SUBSEQUENT_TIMEOUT_PERIOD = 15 * 1000;
- private Context mContext;
private Handler mWebCoreThreadHandler;
private Handler mHandler;
private boolean mPaused;
+ private Set<WebViewClassic> mWebViews;
+
private static WebCoreThreadWatchdog sInstance;
- public synchronized static WebCoreThreadWatchdog start(Context context,
- Handler webCoreThreadHandler) {
+ public synchronized static WebCoreThreadWatchdog start(Handler webCoreThreadHandler) {
if (sInstance == null) {
- sInstance = new WebCoreThreadWatchdog(context, webCoreThreadHandler);
+ sInstance = new WebCoreThreadWatchdog(webCoreThreadHandler);
new Thread(sInstance, "WebCoreThreadWatchdog").start();
}
return sInstance;
}
- public synchronized static void updateContext(Context context) {
+ public synchronized static void registerWebView(WebViewClassic w) {
if (sInstance != null) {
- sInstance.setContext(context);
+ sInstance.addWebView(w);
+ }
+ }
+
+ public synchronized static void unregisterWebView(WebViewClassic w) {
+ if (sInstance != null) {
+ sInstance.removeWebView(w);
}
}
@@ -85,12 +95,18 @@
}
}
- private void setContext(Context context) {
- mContext = context;
+ private void addWebView(WebViewClassic w) {
+ if (mWebViews == null) {
+ mWebViews = new HashSet<WebViewClassic>();
+ }
+ mWebViews.add(w);
}
- private WebCoreThreadWatchdog(Context context, Handler webCoreThreadHandler) {
- mContext = context;
+ private void removeWebView(WebViewClassic w) {
+ mWebViews.remove(w);
+ }
+
+ private WebCoreThreadWatchdog(Handler webCoreThreadHandler) {
mWebCoreThreadHandler = webCoreThreadHandler;
}
@@ -147,39 +163,41 @@
break;
case TIMED_OUT:
- if ((mContext == null) || !(mContext instanceof Activity)) return;
- new AlertDialog.Builder(mContext)
- .setMessage(com.android.internal.R.string.webpage_unresponsive)
- .setPositiveButton(com.android.internal.R.string.force_close,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // User chose to force close.
- Process.killProcess(Process.myPid());
+ boolean postedDialog = false;
+ synchronized (WebCoreThreadWatchdog.class) {
+ Iterator<WebViewClassic> it = mWebViews.iterator();
+ // Check each WebView we are aware of and find one that is capable of
+ // showing the user a prompt dialog.
+ while (it.hasNext()) {
+ WebView activeView = it.next().getWebView();
+
+ if (activeView.getWindowToken() != null &&
+ activeView.getViewRootImpl() != null) {
+ postedDialog = activeView.post(new PageNotRespondingRunnable(
+ activeView.getContext(), this));
+
+ if (postedDialog) {
+ // We placed the message into the UI thread for an attached
+ // WebView so we've made our best attempt to display the
+ // "page not responding" dialog to the user. Although the
+ // message is in the queue, there is no guarantee when/if
+ // the runnable will execute. In the case that the runnable
+ // never executes, the user will need to terminate the
+ // process manually.
+ break;
}
- })
- .setNegativeButton(com.android.internal.R.string.wait,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // The user chose to wait. The last HEARTBEAT message
- // will still be in the WebCore thread's queue, so all
- // we need to do is post another TIMED_OUT so that the
- // user will get prompted again if the WebCore thread
- // doesn't sort itself out.
- sendMessageDelayed(obtainMessage(TIMED_OUT),
- SUBSEQUENT_TIMEOUT_PERIOD);
- }
- })
- .setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- sendMessageDelayed(obtainMessage(TIMED_OUT),
- SUBSEQUENT_TIMEOUT_PERIOD);
- }
- })
- .setIcon(android.R.drawable.ic_dialog_alert)
- .show();
+ }
+ }
+
+ if (!postedDialog) {
+ // There's no active webview we can use to show the dialog, so
+ // wait again. If we never get a usable view, the user will
+ // never get the chance to terminate the process, and will
+ // need to do it manually.
+ sendMessageDelayed(obtainMessage(TIMED_OUT),
+ SUBSEQUENT_TIMEOUT_PERIOD);
+ }
+ }
break;
}
}
@@ -205,4 +223,55 @@
Looper.loop();
}
+
+ private class PageNotRespondingRunnable implements Runnable {
+ Context mContext;
+ private Handler mWatchdogHandler;
+
+ public PageNotRespondingRunnable(Context context, Handler watchdogHandler) {
+ mContext = context;
+ mWatchdogHandler = watchdogHandler;
+ }
+
+ @Override
+ public void run() {
+ // This must run on the UI thread as it is displaying an AlertDialog.
+ assert Looper.getMainLooper().getThread() == Thread.currentThread();
+ new AlertDialog.Builder(mContext)
+ .setMessage(com.android.internal.R.string.webpage_unresponsive)
+ .setPositiveButton(com.android.internal.R.string.force_close,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // User chose to force close.
+ Process.killProcess(Process.myPid());
+ }
+ })
+ .setNegativeButton(com.android.internal.R.string.wait,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // The user chose to wait. The last HEARTBEAT message
+ // will still be in the WebCore thread's queue, so all
+ // we need to do is post another TIMED_OUT so that the
+ // user will get prompted again if the WebCore thread
+ // doesn't sort itself out.
+ mWatchdogHandler.sendMessageDelayed(
+ mWatchdogHandler.obtainMessage(TIMED_OUT),
+ SUBSEQUENT_TIMEOUT_PERIOD);
+ }
+ })
+ .setOnCancelListener(
+ new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ mWatchdogHandler.sendMessageDelayed(
+ mWatchdogHandler.obtainMessage(TIMED_OUT),
+ SUBSEQUENT_TIMEOUT_PERIOD);
+ }
+ })
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .show();
+ }
+ }
}
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index f1f3db2..ee24e5e 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -60,9 +60,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
-import android.provider.Settings;
import android.security.KeyChain;
-import android.speech.tts.TextToSpeech;
import android.text.Editable;
import android.text.InputType;
import android.text.Selection;
@@ -431,14 +429,18 @@
boolean isCharacterDelete = false;
int textLength = text.length();
int originalLength = original.length();
- if (textLength > originalLength) {
- isCharacterAdd = (textLength == originalLength + 1)
- && TextUtils.regionMatches(text, 0, original, 0,
- originalLength);
- } else if (originalLength > textLength) {
- isCharacterDelete = (textLength == originalLength - 1)
- && TextUtils.regionMatches(text, 0, original, 0,
- textLength);
+ int selectionStart = Selection.getSelectionStart(editable);
+ int selectionEnd = Selection.getSelectionEnd(editable);
+ if (selectionStart == selectionEnd) {
+ if (textLength > originalLength) {
+ isCharacterAdd = (textLength == originalLength + 1)
+ && TextUtils.regionMatches(text, 0, original, 0,
+ originalLength);
+ } else if (originalLength > textLength) {
+ isCharacterDelete = (textLength == originalLength - 1)
+ && TextUtils.regionMatches(text, 0, original, 0,
+ textLength);
+ }
}
if (isCharacterAdd) {
sendCharacter(text.charAt(textLength - 1));
@@ -867,15 +869,9 @@
private static final int MOTIONLESS_IGNORE = 3;
private int mHeldMotionless;
- // An instance for injecting accessibility in WebViews with disabled
- // JavaScript or ones for which no accessibility script exists
+ // Lazily-instantiated instance for injecting accessibility.
private AccessibilityInjector mAccessibilityInjector;
- // flag indicating if accessibility script is injected so we
- // know to handle Shift and arrows natively first
- private boolean mAccessibilityScriptInjected;
-
-
/**
* How long the caret handle will last without being touched.
*/
@@ -934,7 +930,6 @@
private static final int RELEASE_SINGLE_TAP = 5;
private static final int REQUEST_FORM_DATA = 6;
private static final int DRAG_HELD_MOTIONLESS = 8;
- private static final int AWAKEN_SCROLL_BARS = 9;
private static final int PREVENT_DEFAULT_TIMEOUT = 10;
private static final int SCROLL_SELECT_TEXT = 11;
@@ -1002,7 +997,7 @@
"REQUEST_FORM_DATA", // = 6;
"RESUME_WEBCORE_PRIORITY", // = 7;
"DRAG_HELD_MOTIONLESS", // = 8;
- "AWAKEN_SCROLL_BARS", // = 9;
+ "", // = 9;
"PREVENT_DEFAULT_TIMEOUT", // = 10;
"SCROLL_SELECT_TEXT" // = 11;
};
@@ -1085,34 +1080,6 @@
private int mHorizontalScrollBarMode = SCROLLBAR_AUTO;
private int mVerticalScrollBarMode = SCROLLBAR_AUTO;
- // constants for determining script injection strategy
- private static final int ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED = -1;
- private static final int ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT = 0;
- private static final int ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED = 1;
-
- // the alias via which accessibility JavaScript interface is exposed
- private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility";
-
- // Template for JavaScript that injects a screen-reader.
- private static final String ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE =
- "javascript:(function() {" +
- " var chooser = document.createElement('script');" +
- " chooser.type = 'text/javascript';" +
- " chooser.src = '%1s';" +
- " document.getElementsByTagName('head')[0].appendChild(chooser);" +
- " })();";
-
- // Regular expression that matches the "axs" URL parameter.
- // The value of 0 means the accessibility script is opted out
- // The value of 1 means the accessibility script is already injected
- private static final String PATTERN_MATCH_AXS_URL_PARAMETER = "(\\?axs=(0|1))|(&axs=(0|1))";
-
- // TextToSpeech instance exposed to JavaScript to the injected screenreader.
- private TextToSpeech mTextToSpeech;
-
- // variable to cache the above pattern in case accessibility is enabled.
- private Pattern mMatchAxsUrlParameterPattern;
-
/**
* Max distance to overscroll by in pixels.
* This how far content can be pulled beyond its normal bounds by the user.
@@ -1598,8 +1565,6 @@
private void init() {
OnTrimMemoryListener.init(mContext);
mWebView.setWillNotDraw(false);
- mWebView.setFocusable(true);
- mWebView.setFocusableInTouchMode(true);
mWebView.setClickable(true);
mWebView.setLongClickable(true);
@@ -1633,40 +1598,6 @@
return true;
}
- /**
- * Adds accessibility APIs to JavaScript.
- *
- * Note: This method is responsible to performing the necessary
- * check if the accessibility APIs should be exposed.
- */
- private void addAccessibilityApisToJavaScript() {
- if (AccessibilityManager.getInstance(mContext).isEnabled()
- && getSettings().getJavaScriptEnabled()) {
- // exposing the TTS for now ...
- final Context ctx = mContext;
- if (ctx != null) {
- final String packageName = ctx.getPackageName();
- if (packageName != null) {
- mTextToSpeech = new TextToSpeech(ctx, null, null,
- packageName + ".**webview**", true);
- addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE);
- }
- }
- }
- }
-
- /**
- * Removes accessibility APIs from JavaScript.
- */
- private void removeAccessibilityApisFromJavaScript() {
- // exposing the TTS for now ...
- if (mTextToSpeech != null) {
- removeJavascriptInterface(ALIAS_ACCESSIBILITY_JS_INTERFACE);
- mTextToSpeech.shutdown();
- mTextToSpeech = null;
- }
- }
-
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
info.setScrollable(isScrollableForAccessibility());
@@ -1687,6 +1618,17 @@
event.setMaxScrollY(Math.max(convertedContentHeight - adjustedViewHeight, 0));
}
+ private boolean isAccessibilityEnabled() {
+ return AccessibilityManager.getInstance(mContext).isEnabled();
+ }
+
+ private AccessibilityInjector getAccessibilityInjector() {
+ if (mAccessibilityInjector == null) {
+ mAccessibilityInjector = new AccessibilityInjector(this);
+ }
+ return mAccessibilityInjector;
+ }
+
private boolean isScrollableForAccessibility() {
return (contentToViewX(getContentWidth()) > getWidth() - mWebView.getPaddingLeft()
- mWebView.getPaddingRight()
@@ -3368,11 +3310,6 @@
nativeSetPauseDrawing(mNativeClass, false);
}
}
- // Ensure that the watchdog has a currently valid Context to be able to display
- // a prompt dialog. For example, if the Activity was finished whilst the WebCore
- // thread was blocked and the Activity is started again, we may reuse the blocked
- // thread, but we'll have a new Activity.
- WebCoreThreadWatchdog.updateContext(mContext);
// We get a call to onResume for new WebViews (i.e. mIsPaused will be false). We need
// to ensure that the Watchdog thread is running for the new WebView, so call
// it outside the if block above.
@@ -3775,7 +3712,6 @@
// Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
mScroller.startScroll(getScrollX(), getScrollY(), dx, dy,
animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
- mWebViewPrivate.awakenScrollBars(mScroller.getDuration());
invalidate();
} else {
mWebView.scrollTo(x, y);
@@ -3828,7 +3764,9 @@
// reset the flag since we set to true in if need after
// loading is see onPageFinished(Url)
- mAccessibilityScriptInjected = false;
+ if (isAccessibilityEnabled()) {
+ getAccessibilityInjector().onPageStarted(url);
+ }
// Don't start out editing.
mIsEditingText = false;
@@ -3840,114 +3778,10 @@
*/
/* package */ void onPageFinished(String url) {
mZoomManager.onPageFinished(url);
- injectAccessibilityForUrl(url);
- }
- /**
- * This method injects accessibility in the loaded document if accessibility
- * is enabled. If JavaScript is enabled we try to inject a URL specific script.
- * If no URL specific script is found or JavaScript is disabled we fallback to
- * the default {@link AccessibilityInjector} implementation.
- * </p>
- * If the URL has the "axs" paramter set to 1 it has already done the
- * script injection so we do nothing. If the parameter is set to 0
- * the URL opts out accessibility script injection so we fall back to
- * the default {@link AccessibilityInjector}.
- * </p>
- * Note: If the user has not opted-in the accessibility script injection no scripts
- * are injected rather the default {@link AccessibilityInjector} implementation
- * is used.
- *
- * @param url The URL loaded by this {@link WebView}.
- */
- private void injectAccessibilityForUrl(String url) {
- if (mWebViewCore == null) {
- return;
+ if (isAccessibilityEnabled()) {
+ getAccessibilityInjector().onPageFinished(url);
}
- AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
-
- if (!accessibilityManager.isEnabled()) {
- // it is possible that accessibility was turned off between reloads
- ensureAccessibilityScriptInjectorInstance(false);
- return;
- }
-
- if (!getSettings().getJavaScriptEnabled()) {
- // no JS so we fallback to the basic buil-in support
- ensureAccessibilityScriptInjectorInstance(true);
- return;
- }
-
- // check the URL "axs" parameter to choose appropriate action
- int axsParameterValue = getAxsUrlParameterValue(url);
- if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED) {
- boolean onDeviceScriptInjectionEnabled = (Settings.Secure.getInt(mContext
- .getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
- if (onDeviceScriptInjectionEnabled) {
- ensureAccessibilityScriptInjectorInstance(false);
- // neither script injected nor script injection opted out => we inject
- mWebView.loadUrl(getScreenReaderInjectingJs());
- // TODO: Set this flag after successfull script injection. Maybe upon injection
- // the chooser should update the meta tag and we check it to declare success
- mAccessibilityScriptInjected = true;
- } else {
- // injection disabled so we fallback to the basic built-in support
- ensureAccessibilityScriptInjectorInstance(true);
- }
- } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT) {
- // injection opted out so we fallback to the basic buil-in support
- ensureAccessibilityScriptInjectorInstance(true);
- } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED) {
- ensureAccessibilityScriptInjectorInstance(false);
- // the URL provides accessibility but we still need to add our generic script
- mWebView.loadUrl(getScreenReaderInjectingJs());
- } else {
- Log.e(LOGTAG, "Unknown URL value for the \"axs\" URL parameter: " + axsParameterValue);
- }
- }
-
- /**
- * Ensures the instance of the {@link AccessibilityInjector} to be present ot not.
- *
- * @param present True to ensure an insance, false to ensure no instance.
- */
- private void ensureAccessibilityScriptInjectorInstance(boolean present) {
- if (present) {
- if (mAccessibilityInjector == null) {
- mAccessibilityInjector = new AccessibilityInjector(this);
- }
- } else {
- mAccessibilityInjector = null;
- }
- }
-
- /**
- * Gets JavaScript that injects a screen-reader.
- *
- * @return The JavaScript snippet.
- */
- private String getScreenReaderInjectingJs() {
- String screenReaderUrl = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL);
- return String.format(ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE, screenReaderUrl);
- }
-
- /**
- * Gets the "axs" URL parameter value.
- *
- * @param url A url to fetch the paramter from.
- * @return The parameter value if such, -1 otherwise.
- */
- private int getAxsUrlParameterValue(String url) {
- if (mMatchAxsUrlParameterPattern == null) {
- mMatchAxsUrlParameterPattern = Pattern.compile(PATTERN_MATCH_AXS_URL_PARAMETER);
- }
- Matcher matcher = mMatchAxsUrlParameterPattern.matcher(url);
- if (matcher.find()) {
- String keyValuePair = url.substring(matcher.start(), matcher.end());
- return Integer.parseInt(keyValuePair.split("=")[1]);
- }
- return -1;
}
// scale from content to view coordinates, and pin
@@ -4158,15 +3992,11 @@
if (mTouchMode == TOUCH_DRAG_MODE) {
if (mHeldMotionless == MOTIONLESS_PENDING) {
mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
- mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
mHeldMotionless = MOTIONLESS_FALSE;
}
if (mHeldMotionless == MOTIONLESS_FALSE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(DRAG_HELD_MOTIONLESS), MOTIONLESS_TIME);
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(AWAKEN_SCROLL_BARS),
- ViewConfiguration.getScrollDefaultDelay());
mHeldMotionless = MOTIONLESS_PENDING;
}
}
@@ -4909,30 +4739,10 @@
return false;
}
- // accessibility support
- if (accessibilityScriptInjected()) {
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- // if an accessibility script is injected we delegate to it the key handling.
- // this script is a screen reader which is a fully fledged solution for blind
- // users to navigate in and interact with web pages.
- sendBatchableInputMessage(EventHub.KEY_DOWN, 0, 0, event);
- return true;
- } else {
- // Clean up if accessibility was disabled after loading the current URL.
- mAccessibilityScriptInjected = false;
- }
- } else if (mAccessibilityInjector != null) {
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- if (mAccessibilityInjector.onKeyEvent(event)) {
- // if an accessibility injector is present (no JavaScript enabled or the site
- // opts out injecting our JavaScript screen reader) we let it decide whether
- // to act on and consume the event.
- return true;
- }
- } else {
- // Clean up if accessibility was disabled after loading the current URL.
- mAccessibilityInjector = null;
- }
+ // See if the accessibility injector needs to handle this event.
+ if (isAccessibilityEnabled()
+ && getAccessibilityInjector().handleKeyEventIfNecessary(event)) {
+ return true;
}
if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
@@ -5036,30 +4846,10 @@
return false;
}
- // accessibility support
- if (accessibilityScriptInjected()) {
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- // if an accessibility script is injected we delegate to it the key handling.
- // this script is a screen reader which is a fully fledged solution for blind
- // users to navigate in and interact with web pages.
- sendBatchableInputMessage(EventHub.KEY_UP, 0, 0, event);
- return true;
- } else {
- // Clean up if accessibility was disabled after loading the current URL.
- mAccessibilityScriptInjected = false;
- }
- } else if (mAccessibilityInjector != null) {
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- if (mAccessibilityInjector.onKeyEvent(event)) {
- // if an accessibility injector is present (no JavaScript enabled or the site
- // opts out injecting our JavaScript screen reader) we let it decide whether to
- // act on and consume the event.
- return true;
- }
- } else {
- // Clean up if accessibility was disabled after loading the current URL.
- mAccessibilityInjector = null;
- }
+ // See if the accessibility injector needs to handle this event.
+ if (isAccessibilityEnabled()
+ && getAccessibilityInjector().handleKeyEventIfNecessary(event)) {
+ return true;
}
if (isEnterActionKey(keyCode)) {
@@ -5360,7 +5150,9 @@
public void onAttachedToWindow() {
if (mWebView.hasWindowFocus()) setActive(true);
- addAccessibilityApisToJavaScript();
+ if (isAccessibilityEnabled()) {
+ getAccessibilityInjector().addAccessibilityApisIfNecessary();
+ }
updateHwAccelerated();
}
@@ -5371,7 +5163,14 @@
mZoomManager.dismissZoomPicker();
if (mWebView.hasWindowFocus()) setActive(false);
- removeAccessibilityApisFromJavaScript();
+ if (isAccessibilityEnabled()) {
+ getAccessibilityInjector().removeAccessibilityApisIfNecessary();
+ } else {
+ // Ensure the injector is cleared if we're detaching from the window
+ // and accessibility is disabled.
+ mAccessibilityInjector = null;
+ }
+
updateHwAccelerated();
if (mWebView.isHardwareAccelerated()) {
@@ -5767,14 +5566,15 @@
return false;
}
- if (!mWebView.isFocused()) {
- mWebView.requestFocus();
- }
-
if (mInputDispatcher == null) {
return false;
}
+ if (mWebView.isFocusable() && mWebView.isFocusableInTouchMode()
+ && !mWebView.isFocused()) {
+ mWebView.requestFocus();
+ }
+
if (mInputDispatcher.postPointerEvent(ev, getScrollX(),
getScrollY() - getTitleHeight(), mZoomManager.getInvScale())) {
mInputDispatcher.dispatchUiEvents();
@@ -6048,27 +5848,6 @@
}
}
- // Turn off scrollbars when dragging a layer.
- if (keepScrollBarsVisible &&
- mTouchMode != TOUCH_DRAG_LAYER_MODE &&
- mTouchMode != TOUCH_DRAG_TEXT_MODE) {
- if (mHeldMotionless != MOTIONLESS_TRUE) {
- mHeldMotionless = MOTIONLESS_TRUE;
- invalidate();
- }
- // keep the scrollbar on the screen even there is no scroll
- mWebViewPrivate.awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(),
- false);
- // Post a message so that we'll keep them alive while we're not scrolling.
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(AWAKEN_SCROLL_BARS),
- ViewConfiguration.getScrollDefaultDelay());
- // return false to indicate that we can't pan out of the
- // view space
- return;
- } else {
- mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
- }
break;
}
case MotionEvent.ACTION_UP: {
@@ -6116,7 +5895,6 @@
case TOUCH_DRAG_LAYER_MODE:
case TOUCH_DRAG_TEXT_MODE:
mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
- mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
// if the user waits a while w/o moving before the
// up, we don't want to do a fling
if (eventTime - mLastTouchTime <= MIN_FLING_TIME) {
@@ -6382,7 +6160,6 @@
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
- mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
removeTouchHighlight();
mHeldMotionless = MOTIONLESS_TRUE;
mTouchMode = TOUCH_DONE_MODE;
@@ -6814,17 +6591,6 @@
// no horizontal overscroll if the content just fits
mScroller.fling(scrollX, scrollY, -vx, -vy, 0, maxX, 0, maxY,
maxX == 0 ? 0 : overflingDistance, overflingDistance);
- // Duration is calculated based on velocity. With range boundaries and overscroll
- // we may not know how long the final animation will take. (Hence the deprecation
- // warning on the call below.) It's not a big deal for scroll bars but if webcore
- // resumes during this effect we will take a performance hit. See computeScroll;
- // we resume webcore there when the animation is finished.
- final int time = mScroller.getDuration();
-
- // Suppress scrollbars for layer scrolling.
- if (mTouchMode != TOUCH_DRAG_LAYER_MODE && mTouchMode != TOUCH_DRAG_TEXT_MODE) {
- mWebViewPrivate.awakenScrollBars(time);
- }
invalidate();
}
@@ -7362,17 +7128,6 @@
case DRAG_HELD_MOTIONLESS:
mHeldMotionless = MOTIONLESS_TRUE;
invalidate();
- // fall through to keep scrollbars awake
-
- case AWAKEN_SCROLL_BARS:
- if (mTouchMode == TOUCH_DRAG_MODE
- && mHeldMotionless == MOTIONLESS_TRUE) {
- mWebViewPrivate.awakenScrollBars(ViewConfiguration
- .getScrollDefaultDelay(), false);
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(AWAKEN_SCROLL_BARS),
- ViewConfiguration.getScrollDefaultDelay());
- }
break;
case SCREEN_ON:
@@ -7467,9 +7222,9 @@
break;
case SELECTION_STRING_CHANGED:
- if (mAccessibilityInjector != null) {
- String selectionString = (String) msg.obj;
- mAccessibilityInjector.onSelectionStringChange(selectionString);
+ if (isAccessibilityEnabled()) {
+ getAccessibilityInjector()
+ .handleSelectionChangedIfNecessary((String) msg.obj);
}
break;
@@ -7538,6 +7293,7 @@
int cursorPosition = start + text.length();
replaceTextfieldText(start, end, text,
cursorPosition, cursorPosition);
+ selectionDone();
break;
}
@@ -7564,7 +7320,9 @@
}
case CLEAR_CARET_HANDLE:
- selectionDone();
+ if (mIsCaretSelection) {
+ selectionDone();
+ }
break;
case KEY_PRESS:
@@ -8025,7 +7783,7 @@
mIsBatchingTextChanges = false;
}
- private void sendBatchableInputMessage(int what, int arg1, int arg2,
+ void sendBatchableInputMessage(int what, int arg1, int arg2,
Object obj) {
if (mWebViewCore == null) {
return;
@@ -8446,16 +8204,6 @@
}
/**
- * @return Whether accessibility script has been injected.
- */
- private boolean accessibilityScriptInjected() {
- // TODO: Maybe the injected script should announce its presence in
- // the page meta-tag so the nativePageShouldHandleShiftAndArrows
- // will check that as one of the conditions it looks for
- return mAccessibilityScriptInjected;
- }
-
- /**
* See {@link WebView#setBackgroundColor(int)}
*/
@Override
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 76cd1c9..af7914e 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -178,8 +178,10 @@
// Start the singleton watchdog which will monitor the WebCore thread
// to verify it's still processing messages.
- WebCoreThreadWatchdog.start(context, sWebCoreHandler);
+ WebCoreThreadWatchdog.start(sWebCoreHandler);
}
+ // Make sure the Watchdog is aware of this new WebView.
+ WebCoreThreadWatchdog.registerWebView(w);
}
// Create an EventHub to handle messages before and after the thread is
// ready.
@@ -1979,6 +1981,7 @@
mEventHub.sendMessageAtFrontOfQueue(
Message.obtain(null, EventHub.DESTROY));
mEventHub.blockMessages();
+ WebCoreThreadWatchdog.unregisterWebView(mWebViewClassic);
}
}
diff --git a/core/java/android/webkit/WebViewInputDispatcher.java b/core/java/android/webkit/WebViewInputDispatcher.java
index 9eeb311..c5a86d8 100644
--- a/core/java/android/webkit/WebViewInputDispatcher.java
+++ b/core/java/android/webkit/WebViewInputDispatcher.java
@@ -822,21 +822,31 @@
}
private void enqueueEventLocked(DispatchEvent d) {
- if (!shouldSkipWebKit(d.mEventType)) {
+ if (!shouldSkipWebKit(d)) {
enqueueWebKitEventLocked(d);
} else {
enqueueUiEventLocked(d);
}
}
- private boolean shouldSkipWebKit(int eventType) {
- switch (eventType) {
+ private boolean shouldSkipWebKit(DispatchEvent d) {
+ switch (d.mEventType) {
case EVENT_TYPE_CLICK:
case EVENT_TYPE_HOVER:
case EVENT_TYPE_SCROLL:
case EVENT_TYPE_HIT_TEST:
return false;
case EVENT_TYPE_TOUCH:
+ // TODO: This should be cleaned up. We now have WebViewInputDispatcher
+ // and WebViewClassic both checking for slop and doing their own
+ // thing - they should be consolidated. And by consolidated, I mean
+ // WebViewClassic's version should just be deleted.
+ // The reason this is done is because webpages seem to expect
+ // that they only get an ontouchmove if the slop has been exceeded.
+ if (mIsTapCandidate && d.mEvent != null
+ && d.mEvent.getActionMasked() == MotionEvent.ACTION_MOVE) {
+ return true;
+ }
return !mPostSendTouchEventsToWebKit
|| mPostDoNotSendTouchEventsToWebKitUntilNextGesture;
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 04c8cdc..8643e9e 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1470,11 +1470,13 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(AbsListView.class.getName());
- if (getFirstVisiblePosition() > 0) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
- }
- if (getLastVisiblePosition() < getCount() - 1) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ if (isEnabled()) {
+ if (getFirstVisiblePosition() > 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
+ if (getLastVisiblePosition() < getCount() - 1) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
}
}
@@ -1485,14 +1487,14 @@
}
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
- if (getLastVisiblePosition() < getCount() - 1) {
+ if (isEnabled() && getLastVisiblePosition() < getCount() - 1) {
final int viewportHeight = getHeight() - mListPadding.top - mListPadding.bottom;
smoothScrollBy(viewportHeight, PositionScroller.SCROLL_DURATION);
return true;
}
} return false;
case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
- if (mFirstPosition > 0) {
+ if (isEnabled() && mFirstPosition > 0) {
final int viewportHeight = getHeight() - mListPadding.top - mListPadding.bottom;
smoothScrollBy(-viewportHeight, PositionScroller.SCROLL_DURATION);
return true;
@@ -2294,17 +2296,19 @@
return;
}
- if (isClickable()) {
+ if (isClickable() && isEnabled()) {
info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
info.setClickable(true);
}
- if (isLongClickable()) {
+ if (isLongClickable() && isEnabled()) {
info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
info.setLongClickable(true);
}
- info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
+ if (isEnabled()) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
+ }
if (position == getSelectedItemPosition()) {
info.setSelected(true);
@@ -2313,34 +2317,40 @@
@Override
public boolean performAccessibilityAction(View host, int action, Bundle arguments) {
+ if (super.performAccessibilityAction(host, action, arguments)) {
+ return true;
+ }
+
final int position = getPositionForView(host);
if (position == INVALID_POSITION) {
return false;
}
+ if (!isEnabled()) {
+ return false;
+ }
+
final long id = getItemIdAtPosition(position);
switch (action) {
- case AccessibilityNodeInfo.ACTION_SELECT:
+ case AccessibilityNodeInfo.ACTION_SELECT: {
setSelection(position);
return true;
- case AccessibilityNodeInfo.ACTION_CLICK:
- if (!super.performAccessibilityAction(host, action, arguments)) {
+ }
+ case AccessibilityNodeInfo.ACTION_CLICK: {
+ if (isClickable()) {
return performItemClick(host, position, id);
}
- return true;
- case AccessibilityNodeInfo.ACTION_LONG_CLICK:
- if (!super.performAccessibilityAction(host, action, arguments)) {
+ } return false;
+ case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
+ if (isLongClickable()) {
return performLongPress(host, position, id);
}
- return true;
- case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
- smoothScrollToPosition(position);
- break;
+ } return false;
}
- return super.performAccessibilityAction(host, action, arguments);
+ return false;
}
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index ae68794..e217e4f 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -21,6 +21,7 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -486,5 +487,46 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(AbsSeekBar.class.getName());
+
+ if (isEnabled()) {
+ final int progress = getProgress();
+ if (progress > 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
+ if (progress < getMax()) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (super.performAccessibilityAction(action, arguments)) {
+ return true;
+ }
+ if (!isEnabled()) {
+ return false;
+ }
+ final int progress = getProgress();
+ final int increment = Math.max(1, Math.round((float) getMax() / 5));
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+ if (progress <= 0) {
+ return false;
+ }
+ setProgress(progress - increment, true);
+ onKeyChange();
+ return true;
+ }
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+ if (progress >= getMax()) {
+ return false;
+ }
+ setProgress(progress + increment, true);
+ onKeyChange();
+ return true;
+ }
+ }
+ return false;
}
}
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index b2c8164..6658fc2 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1369,11 +1369,13 @@
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(Gallery.class.getName());
info.setScrollable(mItemCount > 1);
- if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
- }
- if (mItemCount > 0 && mSelectedPosition > 0) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ if (isEnabled()) {
+ if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
+ if (isEnabled() && mItemCount > 0 && mSelectedPosition > 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
}
}
@@ -1384,13 +1386,13 @@
}
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
- if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
+ if (isEnabled() && mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
final int currentChildIndex = mSelectedPosition - mFirstPosition;
return scrollToChild(currentChildIndex + 1);
}
} return false;
case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
- if (mItemCount > 0 && mSelectedPosition > 0) {
+ if (isEnabled() && mItemCount > 0 && mSelectedPosition > 0) {
final int currentChildIndex = mSelectedPosition - mFirstPosition;
return scrollToChild(currentChildIndex - 1);
}
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index f889cb7..8c6ce19 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -744,6 +744,9 @@
}
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+ if (!isEnabled()) {
+ return false;
+ }
final int viewportWidth = getWidth() - mPaddingLeft - mPaddingRight;
final int targetScrollX = Math.min(mScrollX + viewportWidth, getScrollRange());
if (targetScrollX != mScrollX) {
@@ -752,6 +755,9 @@
}
} return false;
case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+ if (!isEnabled()) {
+ return false;
+ }
final int viewportWidth = getWidth() - mPaddingLeft - mPaddingRight;
final int targetScrollX = Math.max(0, mScrollX - viewportWidth);
if (targetScrollX != mScrollX) {
@@ -770,10 +776,10 @@
final int scrollRange = getScrollRange();
if (scrollRange > 0) {
info.setScrollable(true);
- if (mScrollX > 0) {
+ if (isEnabled() && mScrollX > 0) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
}
- if (mScrollX < scrollRange) {
+ if (isEnabled() && mScrollX < scrollRange) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
}
}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 515f0c4..b60ffc5 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -2173,13 +2173,15 @@
return false;
}
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
- if (getWrapSelectorWheel() || getValue() < getMaxValue()) {
+ if (NumberPicker.this.isEnabled()
+ && (getWrapSelectorWheel() || getValue() < getMaxValue())) {
changeValueByOne(true);
return true;
}
} return false;
case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
- if (getWrapSelectorWheel() || getValue() > getMinValue()) {
+ if (NumberPicker.this.isEnabled()
+ && (getWrapSelectorWheel() || getValue() > getMinValue())) {
changeValueByOne(false);
return true;
}
@@ -2189,20 +2191,23 @@
case VIRTUAL_VIEW_ID_INPUT: {
switch (action) {
case AccessibilityNodeInfo.ACTION_FOCUS: {
- if (!mInputText.isFocused()) {
+ if (NumberPicker.this.isEnabled() && !mInputText.isFocused()) {
return mInputText.requestFocus();
}
} break;
case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: {
- if (mInputText.isFocused()) {
+ if (NumberPicker.this.isEnabled() && mInputText.isFocused()) {
mInputText.clearFocus();
return true;
}
return false;
}
case AccessibilityNodeInfo.ACTION_CLICK: {
- showSoftInput();
- return true;
+ if (NumberPicker.this.isEnabled()) {
+ showSoftInput();
+ return true;
+ }
+ return false;
}
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
if (mAccessibilityFocusedView != virtualViewId) {
@@ -2230,10 +2235,13 @@
case VIRTUAL_VIEW_ID_INCREMENT: {
switch (action) {
case AccessibilityNodeInfo.ACTION_CLICK: {
- NumberPicker.this.changeValueByOne(true);
- sendAccessibilityEventForVirtualView(virtualViewId,
- AccessibilityEvent.TYPE_VIEW_CLICKED);
- } return true;
+ if (NumberPicker.this.isEnabled()) {
+ NumberPicker.this.changeValueByOne(true);
+ sendAccessibilityEventForVirtualView(virtualViewId,
+ AccessibilityEvent.TYPE_VIEW_CLICKED);
+ return true;
+ }
+ } return false;
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
if (mAccessibilityFocusedView != virtualViewId) {
mAccessibilityFocusedView = virtualViewId;
@@ -2257,11 +2265,14 @@
case VIRTUAL_VIEW_ID_DECREMENT: {
switch (action) {
case AccessibilityNodeInfo.ACTION_CLICK: {
- final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT);
- NumberPicker.this.changeValueByOne(increment);
- sendAccessibilityEventForVirtualView(virtualViewId,
- AccessibilityEvent.TYPE_VIEW_CLICKED);
- } return true;
+ if (NumberPicker.this.isEnabled()) {
+ final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT);
+ NumberPicker.this.changeValueByOne(increment);
+ sendAccessibilityEventForVirtualView(virtualViewId,
+ AccessibilityEvent.TYPE_VIEW_CLICKED);
+ return true;
+ }
+ } return false;
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
if (mAccessibilityFocusedView != virtualViewId) {
mAccessibilityFocusedView = virtualViewId;
@@ -2470,7 +2481,9 @@
if (mAccessibilityFocusedView == virtualViewId) {
info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
}
- info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
+ if (NumberPicker.this.isEnabled()) {
+ info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
+ }
return info;
}
@@ -2509,11 +2522,13 @@
if (mAccessibilityFocusedView == View.NO_ID) {
info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
}
- if (getWrapSelectorWheel() || getValue() < getMaxValue()) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
- }
- if (getWrapSelectorWheel() || getValue() > getMinValue()) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ if (NumberPicker.this.isEnabled()) {
+ if (getWrapSelectorWheel() || getValue() < getMaxValue()) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
+ if (getWrapSelectorWheel() || getValue() > getMinValue()) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
}
return info;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 56c4bd8..51c957a 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1445,7 +1445,8 @@
/**
* Returns an estimate of the bitmap heap memory usage for this RemoteViews.
*/
- int estimateMemoryUsage() {
+ /** @hide */
+ public int estimateMemoryUsage() {
return mMemoryUsageCounter.getMemoryUsage();
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index a499743..2a20c56 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -745,6 +745,9 @@
if (super.performAccessibilityAction(action, arguments)) {
return true;
}
+ if (!isEnabled()) {
+ return false;
+ }
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
final int viewportHeight = getHeight() - mPaddingBottom - mPaddingTop;
@@ -770,14 +773,16 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(ScrollView.class.getName());
- final int scrollRange = getScrollRange();
- if (scrollRange > 0) {
- info.setScrollable(true);
- if (mScrollY > 0) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
- }
- if (mScrollY < scrollRange) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ if (isEnabled()) {
+ final int scrollRange = getScrollRange();
+ if (scrollRange > 0) {
+ info.setScrollable(true);
+ if (mScrollY > 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
+ if (mScrollY < scrollRange) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
}
}
}
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index dd0915b..293eda1 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -1230,11 +1230,13 @@
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(StackView.class.getName());
info.setScrollable(getChildCount() > 1);
- if (getDisplayedChild() < getChildCount() - 1) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
- }
- if (getDisplayedChild() > 0) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ if (isEnabled()) {
+ if (getDisplayedChild() < getChildCount() - 1) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
+ if (getDisplayedChild() > 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
}
}
@@ -1243,6 +1245,9 @@
if (super.performAccessibilityAction(action, arguments)) {
return true;
}
+ if (!isEnabled()) {
+ return false;
+ }
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
if (getDisplayedChild() < getChildCount() - 1) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index fc56e11..112881c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7739,8 +7739,7 @@
info.setText(getTextForAccessibility());
}
- if (TextUtils.isEmpty(getContentDescription())
- && !TextUtils.isEmpty(mText)) {
+ if (TextUtils.isEmpty(getContentDescription()) && !TextUtils.isEmpty(mText)) {
info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index 60cd895..6136206 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -79,18 +79,17 @@
private static final int SHOW_ANIMATION_DURATION = 200;
private static final int SHOW_ANIMATION_DELAY = 0;
private static final float TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.3f;
- private static final long RING_EXPAND_DURATION = 200;
private static final float TARGET_INITIAL_POSITION_SCALE = 0.8f;
private TimeInterpolator mChevronAnimationInterpolator = Ease.Quad.easeOut;
private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>();
private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>();
- private ArrayList<Tweener> mChevronAnimations = new ArrayList<Tweener>();
- private ArrayList<Tweener> mTargetAnimations = new ArrayList<Tweener>();
+ private AnimationBundle mChevronAnimations = new AnimationBundle();
+ private AnimationBundle mTargetAnimations = new AnimationBundle();
+ private AnimationBundle mHandleAnimations = new AnimationBundle();
private ArrayList<String> mTargetDescriptions;
private ArrayList<String> mDirectionDescriptions;
- private Tweener mHandleAnimation;
private OnTriggerListener mOnTriggerListener;
private TargetDrawable mHandleDrawable;
private TargetDrawable mOuterRing;
@@ -114,6 +113,33 @@
private boolean mDragging;
private int mNewTargetResources;
+ private class AnimationBundle extends ArrayList<Tweener> {
+ private static final long serialVersionUID = 0xA84D78726F127468L;
+ private boolean mSuspended;
+
+ public void start() {
+ if (mSuspended) return; // ignore attempts to start animations
+ final int count = size();
+ for (int i = 0; i < count; i++) {
+ Tweener anim = get(i);
+ anim.animator.start();
+ }
+ }
+
+ public void stop() {
+ final int count = size();
+ for (int i = 0; i < count; i++) {
+ Tweener anim = get(i);
+ anim.animator.end();
+ }
+ clear();
+ }
+
+ public void setSuspended(boolean suspend) {
+ mSuspended = suspend;
+ }
+ };
+
private AnimatorListener mResetListener = new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animator) {
switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
@@ -239,6 +265,7 @@
a.recycle();
setVibrateEnabled(mVibrationDuration > 0);
+ assignDefaultsIfNeeded();
}
private void dump() {
@@ -254,6 +281,21 @@
Log.v(TAG, "VerticalOffset = " + mVerticalOffset);
}
+ public void suspendAnimations() {
+ mChevronAnimations.setSuspended(true);
+ mTargetAnimations.setSuspended(true);
+ mHandleAnimations.setSuspended(true);
+ }
+
+ public void resumeAnimations() {
+ mChevronAnimations.setSuspended(false);
+ mTargetAnimations.setSuspended(false);
+ mHandleAnimations.setSuspended(false);
+ mChevronAnimations.start();
+ mTargetAnimations.start();
+ mHandleAnimations.start();
+ }
+
@Override
protected int getSuggestedMinimumWidth() {
// View should be large enough to contain the background + handle and
@@ -334,12 +376,12 @@
private void startChevronAnimation() {
final float chevronStartDistance = mHandleDrawable.getWidth() * 0.8f;
final float chevronStopDistance = mOuterRadius * 0.9f / 2.0f;
- mChevronAnimations.clear();
final float startScale = 0.5f;
final float endScale = 2.0f;
-
final int directionCount = mFeedbackCount > 0 ? mChevronDrawables.size()/mFeedbackCount : 0;
+ mChevronAnimations.stop();
+
// Add an animation for all chevron drawables. There are mFeedbackCount drawables
// in each direction and directionCount directions.
for (int direction = 0; direction < directionCount; direction++) {
@@ -367,24 +409,21 @@
"onUpdate", mUpdateListener));
}
}
+ mChevronAnimations.start();
}
private void stopChevronAnimation() {
- for (Tweener anim : mChevronAnimations) {
- anim.animator.end();
- }
- mChevronAnimations.clear();
+ mChevronAnimations.stop();
}
private void stopHandleAnimation() {
- if (mHandleAnimation != null) {
- mHandleAnimation.animator.end();
- mHandleAnimation = null;
- }
+ mHandleAnimations.stop();
}
private void deactivateTargets() {
- for (TargetDrawable target : mTargetDrawables) {
+ final int count = mTargetDrawables.size();
+ for (int i = 0; i < count; i++) {
+ TargetDrawable target = mTargetDrawables.get(i);
target.setState(TargetDrawable.STATE_INACTIVE);
}
mActiveTarget = -1;
@@ -445,14 +484,16 @@
// Animate handle back to the center based on current state.
int delay = targetHit ? RETURN_TO_HOME_DELAY : 0;
int duration = targetHit ? 0 : RETURN_TO_HOME_DURATION;
- mHandleAnimation = Tweener.to(mHandleDrawable, duration,
+ mHandleAnimations.stop();
+ mHandleAnimations.add(Tweener.to(mHandleDrawable, duration,
"ease", Ease.Quart.easeOut,
"delay", delay,
"alpha", 1.0f,
"x", 0,
"y", 0,
"onUpdate", mUpdateListener,
- "onComplete", (mDragging && !targetHit) ? mResetListenerWithPing : mResetListener);
+ "onComplete", (mDragging && !targetHit) ? mResetListenerWithPing : mResetListener));
+ mHandleAnimations.start();
setGrabbedState(OnTriggerListener.NO_HANDLE);
}
@@ -467,9 +508,7 @@
}
private void hideTargets(boolean animate) {
- if (mTargetAnimations.size() > 0) {
- stopTargetAnimation();
- }
+ mTargetAnimations.stop();
// Note: these animations should complete at the same time so that we can swap out
// the target assets asynchronously from the setTargetResources() call.
mAnimatingTargets = animate;
@@ -497,12 +536,12 @@
"delay", delay,
"onUpdate", mUpdateListener,
"onComplete", mTargetUpdateListener));
+
+ mTargetAnimations.start();
}
private void showTargets(boolean animate) {
- if (mTargetAnimations.size() > 0) {
- stopTargetAnimation();
- }
+ mTargetAnimations.stop();
mAnimatingTargets = animate;
final int delay = animate ? SHOW_ANIMATION_DELAY : 0;
final int length = mTargetDrawables.size();
@@ -521,7 +560,7 @@
}
mOuterRing.setScaleX(0.5f);
mOuterRing.setScaleY(0.5f);
- mTargetAnimations.add(Tweener.to(mOuterRing, animate ? RING_EXPAND_DURATION : 0,
+ mTargetAnimations.add(Tweener.to(mOuterRing, animate ? SHOW_ANIMATION_DURATION : 0,
"ease", Ease.Cubic.easeOut,
"alpha", 1.0f,
"scaleX", 1.0f,
@@ -529,13 +568,12 @@
"delay", delay,
"onUpdate", mUpdateListener,
"onComplete", mTargetUpdateListener));
+
+ mTargetAnimations.start();
}
private void stopTargetAnimation() {
- for (Tweener anim : mTargetAnimations) {
- anim.animator.end();
- }
- mTargetAnimations.clear();
+ mTargetAnimations.stop();
}
private void vibrate() {
@@ -658,7 +696,6 @@
*
*/
public void ping() {
- stopChevronAnimation();
startChevronAnimation();
}
@@ -721,7 +758,7 @@
}
private void handleDown(MotionEvent event) {
- if (!trySwitchToFirstTouchState(event)) {
+ if (!trySwitchToFirstTouchState(event.getX(), event.getY())) {
mDragging = false;
stopTargetAnimation();
ping();
@@ -747,14 +784,11 @@
}
private void handleMove(MotionEvent event) {
- if (!mDragging) {
- trySwitchToFirstTouchState(event);
- return;
- }
-
int activeTarget = -1;
final int historySize = event.getHistorySize();
- final boolean singleTarget = mTargetDrawables.size() == 1;
+ ArrayList<TargetDrawable> targets = mTargetDrawables;
+ int ntargets = targets.size();
+ final boolean singleTarget = ntargets == 1;
float x = 0.0f;
float y = 0.0f;
for (int k = 0; k < historySize + 1; k++) {
@@ -768,25 +802,29 @@
float limitX = tx * scale;
float limitY = ty * scale;
- if (singleTarget) {
- // Snap to outer ring if there's only one target
- float snapRadius = mOuterRadius - mSnapMargin;
- if (touchRadius > snapRadius) {
- activeTarget = 0;
- }
+ if (!mDragging) {
+ trySwitchToFirstTouchState(eventX, eventY);
} else {
- // If there's more than one target, snap to the closest one less than hitRadius away.
- float best = Float.MAX_VALUE;
- final float hitRadius2 = mHitRadius * mHitRadius;
- for (int i = 0; i < mTargetDrawables.size(); i++) {
- // Snap to the first target in range
- TargetDrawable target = mTargetDrawables.get(i);
- float dx = limitX - target.getX();
- float dy = limitY - target.getY();
- float dist2 = dx*dx + dy*dy;
- if (target.isEnabled() && dist2 < hitRadius2 && dist2 < best) {
- activeTarget = i;
- best = dist2;
+ if (singleTarget) {
+ // Snap to outer ring if there's only one target
+ float snapRadius = mOuterRadius - mSnapMargin;
+ if (touchRadius > snapRadius) {
+ activeTarget = 0;
+ }
+ } else {
+ // For more than one target, snap to the closest one less than hitRadius away.
+ float best = Float.MAX_VALUE;
+ final float hitRadius2 = mHitRadius * mHitRadius;
+ for (int i = 0; i < ntargets; i++) {
+ // Snap to the first target in range
+ TargetDrawable target = targets.get(i);
+ float dx = limitX - target.getX();
+ float dy = limitY - target.getY();
+ float dist2 = dx*dx + dy*dy;
+ if (target.isEnabled() && dist2 < hitRadius2 && dist2 < best) {
+ activeTarget = i;
+ best = dist2;
+ }
}
}
}
@@ -794,9 +832,13 @@
y = limitY;
}
+ if (!mDragging) {
+ return;
+ }
+
if (activeTarget != -1) {
switchToState(STATE_SNAP, x,y);
- TargetDrawable target = mTargetDrawables.get(activeTarget);
+ TargetDrawable target = targets.get(activeTarget);
float newX = singleTarget ? x : target.getX();
float newY = singleTarget ? y : target.getY();
moveHandleTo(newX, newY, false);
@@ -812,7 +854,7 @@
if (mActiveTarget != activeTarget) {
// Defocus the old target
if (mActiveTarget != -1) {
- TargetDrawable target = mTargetDrawables.get(mActiveTarget);
+ TargetDrawable target = targets.get(mActiveTarget);
if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
target.setState(TargetDrawable.STATE_INACTIVE);
mHandleDrawable.setAlpha(1.0f);
@@ -820,7 +862,7 @@
}
// Focus the new target
if (activeTarget != -1) {
- TargetDrawable target = mTargetDrawables.get(activeTarget);
+ TargetDrawable target = targets.get(activeTarget);
if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
target.setState(TargetDrawable.STATE_FOCUSED);
mHandleDrawable.setAlpha(0.0f);
@@ -877,9 +919,7 @@
}
}
- private boolean trySwitchToFirstTouchState(MotionEvent event) {
- final float x = event.getX();
- final float y = event.getY();
+ private boolean trySwitchToFirstTouchState(float x, float y) {
final float tx = x - mWaveCenterX;
final float ty = y - mWaveCenterY;
if (mAlwaysTrackFinger || dist2(tx,ty) <= getScaledTapRadiusSquared()) {
@@ -892,9 +932,9 @@
return false;
}
- private void assignDefaultsIfNeeded(float centerX, float centerY) {
+ private void assignDefaultsIfNeeded() {
if (mOuterRadius == 0.0f) {
- mOuterRadius = 0.5f*(float) Math.hypot(centerX, centerY);
+ mOuterRadius = Math.max(mOuterRing.getWidth(), mOuterRing.getHeight())/2.0f;
}
if (mHitRadius == 0.0f) {
// Use the radius of inscribed circle of the first target.
@@ -941,6 +981,7 @@
super.onLayout(changed, left, top, right, bottom);
final int width = right - left;
final int height = bottom - top;
+
// Target placement width/height. This puts the targets on the greater of the ring
// width or the specified outer radius.
final float placementWidth = Math.max(mOuterRing.getWidth(), 2 * mOuterRadius);
@@ -950,8 +991,6 @@
float newWaveCenterY = mVerticalOffset + mVerticalInset
+ Math.max(height, + mMaxTargetHeight + placementHeight) / 2;
- assignDefaultsIfNeeded(newWaveCenterX, newWaveCenterY);
-
if (mInitialLayout) {
hideChevrons();
hideTargets(false);
@@ -976,9 +1015,12 @@
private void updateTargetPositions(float centerX, float centerY) {
// Reposition the target drawables if the view changed.
- for (int i = 0; i < mTargetDrawables.size(); i++) {
- final TargetDrawable targetIcon = mTargetDrawables.get(i);
- double angle = -2.0f * Math.PI * i / mTargetDrawables.size();
+ ArrayList<TargetDrawable> targets = mTargetDrawables;
+ final int size = targets.size();
+ final float alpha = (float) (-2.0f * Math.PI / size);
+ for (int i = 0; i < size; i++) {
+ final TargetDrawable targetIcon = targets.get(i);
+ final float angle = alpha * i;
targetIcon.setPositionX(centerX);
targetIcon.setPositionY(centerY);
targetIcon.setX(mOuterRadius * (float) Math.cos(angle));
@@ -987,7 +1029,10 @@
}
private void updateChevronPositions(float centerX, float centerY) {
- for (TargetDrawable target : mChevronDrawables) {
+ ArrayList<TargetDrawable> chevrons = mChevronDrawables;
+ final int size = chevrons.size();
+ for (int i = 0; i < size; i++) {
+ TargetDrawable target = chevrons.get(i);
if (target != null) {
target.setPositionX(centerX);
target.setPositionY(centerY);
@@ -996,7 +1041,10 @@
}
private void hideChevrons() {
- for (TargetDrawable chevron : mChevronDrawables) {
+ ArrayList<TargetDrawable> chevrons = mChevronDrawables;
+ final int size = chevrons.size();
+ for (int i = 0; i < size; i++) {
+ TargetDrawable chevron = chevrons.get(i);
if (chevron != null) {
chevron.setAlpha(0.0f);
}
@@ -1006,14 +1054,18 @@
@Override
protected void onDraw(Canvas canvas) {
mOuterRing.draw(canvas);
- for (TargetDrawable target : mTargetDrawables) {
+ final int ntargets = mTargetDrawables.size();
+ for (int i = 0; i < ntargets; i++) {
+ TargetDrawable target = mTargetDrawables.get(i);
if (target != null) {
target.draw(canvas);
}
}
- for (TargetDrawable target : mChevronDrawables) {
- if (target != null) {
- target.draw(canvas);
+ final int nchevrons = mChevronDrawables.size();
+ for (int i = 0; i < nchevrons; i++) {
+ TargetDrawable chevron = mChevronDrawables.get(i);
+ if (chevron != null) {
+ chevron.draw(canvas);
}
}
mHandleDrawable.draw(canvas);
diff --git a/core/java/com/android/internal/widget/multiwaveview/Tweener.java b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
index bc8a62f..1d502ba 100644
--- a/core/java/com/android/internal/widget/multiwaveview/Tweener.java
+++ b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
@@ -122,7 +122,6 @@
anim.addListener(listener);
}
anim.addListener(mCleanupListener);
- anim.start();
return tween;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index dbc60f9..e3082ea 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1551,6 +1551,14 @@
android:description="@string/permdesc_bindInputMethod"
android:protectionLevel="signature" />
+ <!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
+ to ensure that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:label="@string/permlab_bindAccessibilityService"
+ android:description="@string/permdesc_bindAccessibilityService"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a TextService (e.g. SpellCheckerService)
to ensure that only the system can bind to it. -->
<permission android:name="android.permission.BIND_TEXT_SERVICE"
diff --git a/core/res/res/anim-land/task_close_enter.xml b/core/res/res/anim-land/task_close_enter.xml
index 805ff6c..facc42b 100644
--- a/core/res/res/anim-land/task_close_enter.xml
+++ b/core/res/res/anim-land/task_close_enter.xml
@@ -23,21 +23,20 @@
<alpha android:fromAlpha="0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350"/>
+ android:startOffset="300"
+ android:duration="400"/>
- <translate android:fromXDelta="-140%" android:toXDelta="0"
+ <translate android:fromXDelta="-120%" android:toXDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_cubic"
- android:startOffset="150"
- android:duration="350"/>
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="300"
+ android:duration="400" />
- <scale android:fromXScale=".6" android:toXScale="1.0"
- android:fromYScale=".6" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="50%p"
+ <scale android:fromXScale=".5" android:toXScale="1.0"
+ android:fromYScale=".5" android:toYScale="1.0"
+ android:pivotY="50%p" android:pivotX="0%p"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350" />
-
+ android:startOffset="300"
+ android:duration="400" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_close_exit.xml b/core/res/res/anim-land/task_close_exit.xml
index 3e97149..e104c33 100644
--- a/core/res/res/anim-land/task_close_exit.xml
+++ b/core/res/res/anim-land/task_close_exit.xml
@@ -19,25 +19,25 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
<alpha android:fromAlpha="1.0" android:toAlpha="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/accelerate_quad"
- android:duration="350"/>
+ android:duration="300"/>
- <translate android:fromXDelta="0" android:toXDelta="140%"
+ <translate android:fromXDelta="0" android:toXDelta="120%"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:duration="350"/>
+ android:interpolator="@interpolator/accelerate_cubic"
+ android:duration="300"/>
- <scale android:fromXScale="1.0" android:toXScale="0.6"
- android:fromYScale="1.0" android:toYScale="0.6"
+ <scale android:fromXScale="1.0" android:toXScale="0.5"
+ android:fromYScale="1.0" android:toYScale="0.5"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/decelerate_cubic"
- android:duration="350" />
+ android:pivotY="50%p" android:pivotX="100%p"
+ android:interpolator="@interpolator/accelerate_quad"
+ android:duration="300" />
<!-- This is needed to keep the animation running while task_open_enter completes -->
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="500" />
+ android:duration="700" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_open_enter.xml b/core/res/res/anim-land/task_open_enter.xml
index fb1c5d6..dc7c7a9 100644
--- a/core/res/res/anim-land/task_open_enter.xml
+++ b/core/res/res/anim-land/task_open_enter.xml
@@ -23,21 +23,20 @@
<alpha android:fromAlpha="0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350"/>
+ android:startOffset="300"
+ android:duration="400"/>
- <translate android:fromXDelta="140%" android:toXDelta="0"
+ <translate android:fromXDelta="120%" android:toXDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_cubic"
- android:startOffset="150"
- android:duration="350"/>
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="300"
+ android:duration="400" />
- <scale android:fromXScale=".6" android:toXScale="1.0"
- android:fromYScale=".6" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="50%p"
+ <scale android:fromXScale=".5" android:toXScale="1.0"
+ android:fromYScale=".5" android:toYScale="1.0"
+ android:pivotY="50%p" android:pivotX="100%p"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350" />
-
+ android:startOffset="300"
+ android:duration="400" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_open_exit.xml b/core/res/res/anim-land/task_open_exit.xml
index 8d15324..701afa6 100644
--- a/core/res/res/anim-land/task_open_exit.xml
+++ b/core/res/res/anim-land/task_open_exit.xml
@@ -19,25 +19,25 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
<alpha android:fromAlpha="1.0" android:toAlpha="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/accelerate_quad"
- android:duration="350"/>
+ android:duration="300"/>
- <translate android:fromXDelta="0" android:toXDelta="-140%"
+ <translate android:fromXDelta="0" android:toXDelta="-120%"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:duration="350"/>
+ android:interpolator="@interpolator/accelerate_cubic"
+ android:duration="300"/>
- <scale android:fromXScale="1.0" android:toXScale="0.6"
- android:fromYScale="1.0" android:toYScale="0.6"
+ <scale android:fromXScale="1.0" android:toXScale="0.5"
+ android:fromYScale="1.0" android:toYScale="0.5"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/decelerate_cubic"
- android:duration="350" />
+ android:pivotY="50%p" android:pivotX="0%p"
+ android:interpolator="@interpolator/accelerate_quad"
+ android:duration="300" />
<!-- This is needed to keep the animation running while task_open_enter completes -->
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="500" />
+ android:duration="700" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-port/task_close_enter.xml b/core/res/res/anim-port/task_close_enter.xml
index 1806eed..9a747a1 100644
--- a/core/res/res/anim-port/task_close_enter.xml
+++ b/core/res/res/anim-port/task_close_enter.xml
@@ -23,21 +23,20 @@
<alpha android:fromAlpha="0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350"/>
+ android:startOffset="300"
+ android:duration="400"/>
- <translate android:fromYDelta="-140%" android:toYDelta="0"
+ <translate android:fromYDelta="-120%" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_cubic"
- android:startOffset="150"
- android:duration="350"/>
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="300"
+ android:duration="400" />
- <scale android:fromXScale=".6" android:toXScale="1.0"
- android:fromYScale=".6" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="50%p"
+ <scale android:fromXScale=".5" android:toXScale="1.0"
+ android:fromYScale=".5" android:toYScale="1.0"
+ android:pivotX="50%p" android:pivotY="0%p"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350" />
-
+ android:startOffset="300"
+ android:duration="400" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-port/task_close_exit.xml b/core/res/res/anim-port/task_close_exit.xml
index 958a7a2..35b1aa3 100644
--- a/core/res/res/anim-port/task_close_exit.xml
+++ b/core/res/res/anim-port/task_close_exit.xml
@@ -19,25 +19,25 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
<alpha android:fromAlpha="1.0" android:toAlpha="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/accelerate_quad"
- android:duration="350"/>
+ android:duration="300"/>
- <translate android:fromYDelta="0" android:toYDelta="140%"
+ <translate android:fromYDelta="0" android:toYDelta="120%"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:duration="350"/>
+ android:interpolator="@interpolator/accelerate_cubic"
+ android:duration="300"/>
- <scale android:fromXScale="1.0" android:toXScale="0.6"
- android:fromYScale="1.0" android:toYScale="0.6"
+ <scale android:fromXScale="1.0" android:toXScale="0.5"
+ android:fromYScale="1.0" android:toYScale="0.5"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/decelerate_cubic"
- android:duration="350" />
+ android:pivotX="50%p" android:pivotY="100%p"
+ android:interpolator="@interpolator/accelerate_quad"
+ android:duration="300" />
<!-- This is needed to keep the animation running while task_open_enter completes -->
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="500" />
+ android:duration="700" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-port/task_open_enter.xml b/core/res/res/anim-port/task_open_enter.xml
index 54a2d93..5e4ae18 100644
--- a/core/res/res/anim-port/task_open_enter.xml
+++ b/core/res/res/anim-port/task_open_enter.xml
@@ -23,21 +23,20 @@
<alpha android:fromAlpha="0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350"/>
+ android:startOffset="300"
+ android:duration="400"/>
- <translate android:fromYDelta="140%" android:toYDelta="0"
+ <translate android:fromYDelta="120%" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_cubic"
- android:startOffset="150"
- android:duration="350"/>
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="300"
+ android:duration="400" />
- <scale android:fromXScale=".6" android:toXScale="1.0"
- android:fromYScale=".6" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="50%p"
+ <scale android:fromXScale=".5" android:toXScale="1.0"
+ android:fromYScale=".5" android:toYScale="1.0"
+ android:pivotX="50%p" android:pivotY="100%p"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350" />
-
+ android:startOffset="300"
+ android:duration="400" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-port/task_open_exit.xml b/core/res/res/anim-port/task_open_exit.xml
index 18e6550b..0ba35d7 100644
--- a/core/res/res/anim-port/task_open_exit.xml
+++ b/core/res/res/anim-port/task_open_exit.xml
@@ -19,25 +19,25 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
<alpha android:fromAlpha="1.0" android:toAlpha="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/accelerate_quad"
- android:duration="350"/>
+ android:duration="300"/>
- <translate android:fromYDelta="0" android:toYDelta="-140%"
+ <translate android:fromYDelta="0" android:toYDelta="-120%"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:duration="350"/>
+ android:interpolator="@interpolator/accelerate_cubic"
+ android:duration="300"/>
- <scale android:fromXScale="1.0" android:toXScale="0.6"
- android:fromYScale="1.0" android:toYScale="0.6"
+ <scale android:fromXScale="1.0" android:toXScale="0.5"
+ android:fromYScale="1.0" android:toYScale="0.5"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/decelerate_cubic"
- android:duration="350" />
+ android:pivotX="50%p" android:pivotY="0%p"
+ android:interpolator="@interpolator/accelerate_quad"
+ android:duration="300" />
<!-- This is needed to keep the animation running while task_open_enter completes -->
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="500" />
+ android:duration="700" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_close_enter.xml b/core/res/res/anim-sw720dp/task_close_enter.xml
index 1806eed..9a747a1 100644
--- a/core/res/res/anim-sw720dp/task_close_enter.xml
+++ b/core/res/res/anim-sw720dp/task_close_enter.xml
@@ -23,21 +23,20 @@
<alpha android:fromAlpha="0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350"/>
+ android:startOffset="300"
+ android:duration="400"/>
- <translate android:fromYDelta="-140%" android:toYDelta="0"
+ <translate android:fromYDelta="-120%" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_cubic"
- android:startOffset="150"
- android:duration="350"/>
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="300"
+ android:duration="400" />
- <scale android:fromXScale=".6" android:toXScale="1.0"
- android:fromYScale=".6" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="50%p"
+ <scale android:fromXScale=".5" android:toXScale="1.0"
+ android:fromYScale=".5" android:toYScale="1.0"
+ android:pivotX="50%p" android:pivotY="0%p"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350" />
-
+ android:startOffset="300"
+ android:duration="400" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_close_exit.xml b/core/res/res/anim-sw720dp/task_close_exit.xml
index 958a7a2..35b1aa3 100644
--- a/core/res/res/anim-sw720dp/task_close_exit.xml
+++ b/core/res/res/anim-sw720dp/task_close_exit.xml
@@ -19,25 +19,25 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
<alpha android:fromAlpha="1.0" android:toAlpha="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/accelerate_quad"
- android:duration="350"/>
+ android:duration="300"/>
- <translate android:fromYDelta="0" android:toYDelta="140%"
+ <translate android:fromYDelta="0" android:toYDelta="120%"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:duration="350"/>
+ android:interpolator="@interpolator/accelerate_cubic"
+ android:duration="300"/>
- <scale android:fromXScale="1.0" android:toXScale="0.6"
- android:fromYScale="1.0" android:toYScale="0.6"
+ <scale android:fromXScale="1.0" android:toXScale="0.5"
+ android:fromYScale="1.0" android:toYScale="0.5"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/decelerate_cubic"
- android:duration="350" />
+ android:pivotX="50%p" android:pivotY="100%p"
+ android:interpolator="@interpolator/accelerate_quad"
+ android:duration="300" />
<!-- This is needed to keep the animation running while task_open_enter completes -->
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="500" />
+ android:duration="700" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_open_enter.xml b/core/res/res/anim-sw720dp/task_open_enter.xml
index 54a2d93..5e4ae18 100644
--- a/core/res/res/anim-sw720dp/task_open_enter.xml
+++ b/core/res/res/anim-sw720dp/task_open_enter.xml
@@ -23,21 +23,20 @@
<alpha android:fromAlpha="0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350"/>
+ android:startOffset="300"
+ android:duration="400"/>
- <translate android:fromYDelta="140%" android:toYDelta="0"
+ <translate android:fromYDelta="120%" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_cubic"
- android:startOffset="150"
- android:duration="350"/>
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="300"
+ android:duration="400" />
- <scale android:fromXScale=".6" android:toXScale="1.0"
- android:fromYScale=".6" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="50%p"
+ <scale android:fromXScale=".5" android:toXScale="1.0"
+ android:fromYScale=".5" android:toYScale="1.0"
+ android:pivotX="50%p" android:pivotY="100%p"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="150"
- android:duration="350" />
-
+ android:startOffset="300"
+ android:duration="400" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_open_exit.xml b/core/res/res/anim-sw720dp/task_open_exit.xml
index 18e6550b..0ba35d7 100644
--- a/core/res/res/anim-sw720dp/task_open_exit.xml
+++ b/core/res/res/anim-sw720dp/task_open_exit.xml
@@ -19,25 +19,25 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
<alpha android:fromAlpha="1.0" android:toAlpha="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/accelerate_quad"
- android:duration="350"/>
+ android:duration="300"/>
- <translate android:fromYDelta="0" android:toYDelta="-140%"
+ <translate android:fromYDelta="0" android:toYDelta="-120%"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:duration="350"/>
+ android:interpolator="@interpolator/accelerate_cubic"
+ android:duration="300"/>
- <scale android:fromXScale="1.0" android:toXScale="0.6"
- android:fromYScale="1.0" android:toYScale="0.6"
+ <scale android:fromXScale="1.0" android:toXScale="0.5"
+ android:fromYScale="1.0" android:toYScale="0.5"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/decelerate_cubic"
- android:duration="350" />
+ android:pivotX="50%p" android:pivotY="0%p"
+ android:interpolator="@interpolator/accelerate_quad"
+ android:duration="300" />
<!-- This is needed to keep the animation running while task_open_enter completes -->
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="500" />
+ android:duration="700" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_open_enter.xml b/core/res/res/anim/wallpaper_open_enter.xml
index ee7ab60..12a1bdf 100644
--- a/core/res/res/anim/wallpaper_open_enter.xml
+++ b/core/res/res/anim/wallpaper_open_enter.xml
@@ -21,5 +21,5 @@
android:detachWallpaper="true" android:shareInterpolator="false" android:zAdjustment="normal">
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="300"/>
+ android:duration="375"/>
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml
index 905743e..b0f97d1 100644
--- a/core/res/res/anim/wallpaper_open_exit.xml
+++ b/core/res/res/anim/wallpaper_open_exit.xml
@@ -20,13 +20,13 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" android:zAdjustment="top">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:interpolator="@interpolator/linear"
+ android:interpolator="@interpolator/accelerate_decelerate"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:duration="200" />
- <scale android:fromXScale="1.0" android:toXScale="0.4"
- android:fromYScale="1.0" android:toYScale="0.4"
+ <scale android:fromXScale="1.0" android:toXScale="0.5"
+ android:fromYScale="1.0" android:toYScale="0.5"
android:pivotX="50%p" android:pivotY="50%p"
android:interpolator="@interpolator/decelerate_quad"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="250" />
+ android:duration="375" />
</set>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_action.xml b/core/res/res/layout/notification_action.xml
index 28812a9..33cbab9 100644
--- a/core/res/res/layout/notification_action.xml
+++ b/core/res/res/layout/notification_action.xml
@@ -17,11 +17,14 @@
<Button xmlns:android="http://schemas.android.com/apk/res/android"
style="?android:attr/borderlessButtonStyle"
android:id="@+id/action0"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="48dp"
+ android:layout_weight="1"
android:gravity="left|center_vertical"
android:drawablePadding="8dp"
android:paddingLeft="8dp"
android:textColor="#ccc"
android:textSize="14dp"
+ android:singleLine="true"
+ android:ellipsize="end"
/>
diff --git a/core/res/res/layout/notification_action_list.xml b/core/res/res/layout/notification_action_list.xml
new file mode 100644
index 0000000..fa0a8c8
--- /dev/null
+++ b/core/res/res/layout/notification_action_list.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/actions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:visibility="gone"
+ android:showDividers="middle"
+ android:divider="?android:attr/listDivider"
+ >
+ <!-- actions will be added here -->
+</LinearLayout>
diff --git a/core/res/res/layout/notification_action_tombstone.xml b/core/res/res/layout/notification_action_tombstone.xml
index e61e15f..992b37c 100644
--- a/core/res/res/layout/notification_action_tombstone.xml
+++ b/core/res/res/layout/notification_action_tombstone.xml
@@ -15,12 +15,18 @@
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ style="?android:attr/borderlessButtonStyle"
android:id="@+id/action0"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="48dp"
+ android:layout_weight="1"
android:gravity="left|center_vertical"
android:drawablePadding="8dp"
android:paddingLeft="8dp"
- android:textColor="#666"
+ android:textColor="#ccc"
android:textSize="14dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:alpha="0.5"
+ android:enabled="false"
/>
diff --git a/core/res/res/layout/notification_template_big_base.xml b/core/res/res/layout/notification_template_big_base.xml
index 378161c..d50b792 100644
--- a/core/res/res/layout/notification_template_big_base.xml
+++ b/core/res/res/layout/notification_template_big_base.xml
@@ -143,14 +143,11 @@
style="?android:attr/progressBarStyleHorizontal"
/>
</LinearLayout>
- <LinearLayout
+ <include
+ layout="@layout/notification_action_list"
android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone"
- >
- <!-- actions will be added here -->
- </LinearLayout>
+ />
</LinearLayout>
</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_picture.xml b/core/res/res/layout/notification_template_big_picture.xml
index 51e46b2..f98970a 100644
--- a/core/res/res/layout/notification_template_big_picture.xml
+++ b/core/res/res/layout/notification_template_big_picture.xml
@@ -27,11 +27,12 @@
android:id="@+id/big_picture"
android:layout_width="match_parent"
android:layout_height="192dp"
+ android:layout_marginTop="64dp"
+ android:layout_gravity="bottom"
android:scaleType="centerCrop"
/>
<include layout="@layout/notification_template_base"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="192dp"
/>
</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_text.xml b/core/res/res/layout/notification_template_big_text.xml
index 77a5f11..210bc13 100644
--- a/core/res/res/layout/notification_template_big_text.xml
+++ b/core/res/res/layout/notification_template_big_text.xml
@@ -105,16 +105,13 @@
android:layout_weight="1"
/>
</LinearLayout>
- <LinearLayout
- android:id="@+id/actions"
+ <include
+ layout="@layout/notification_action_list"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:orientation="vertical"
android:visibility="gone"
android:layout_weight="1"
- >
- <!-- actions will be added here -->
- </LinearLayout>
+ />
<TextView android:id="@+id/overflow_title"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_template_inbox.xml b/core/res/res/layout/notification_template_inbox.xml
index 05ec1d8..eb5e759 100644
--- a/core/res/res/layout/notification_template_inbox.xml
+++ b/core/res/res/layout/notification_template_inbox.xml
@@ -93,8 +93,6 @@
android:layout_height="0dp"
android:singleLine="true"
android:ellipsize="end"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
android:visibility="gone"
android:layout_weight="1"
/>
@@ -104,8 +102,6 @@
android:layout_height="0dp"
android:singleLine="true"
android:ellipsize="end"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
android:visibility="gone"
android:layout_weight="1"
/>
@@ -115,8 +111,6 @@
android:layout_height="0dp"
android:singleLine="true"
android:ellipsize="end"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
android:visibility="gone"
android:layout_weight="1"
/>
@@ -126,8 +120,6 @@
android:layout_height="0dp"
android:singleLine="true"
android:ellipsize="end"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
android:visibility="gone"
android:layout_weight="1"
/>
@@ -137,21 +129,16 @@
android:layout_height="0dp"
android:singleLine="true"
android:ellipsize="end"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
android:visibility="gone"
android:layout_weight="1"
/>
- <LinearLayout
+ <include
+ layout="@layout/notification_action_list"
android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
android:layout_weight="0"
- android:visibility="gone"
- >
- <!-- actions will be added here -->
- </LinearLayout>
+ />
<TextView android:id="@+id/overflow_title"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="match_parent"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b739835..732b0ab 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -176,9 +176,9 @@
<string name="permgrouplab_network" msgid="5808983377727109831">"Netwerkkommunikasie"</string>
<string name="permgroupdesc_network" msgid="4478299413241861987">"Kry toegang tot verskeie netwerkfunksies."</string>
<string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
- <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Toegangstoestelle en netwerke deur Bluetooth."</string>
+ <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Kry toegang tot toestelle en netwerke deur Bluetooth."</string>
<string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Kortreeks-netwerke"</string>
- <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Toegangstoestelle met kortreeks-netwerke soos NFC."</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Kry toegang tot toestelle met kortreeks-netwerke soos NFC."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Oudio-instellings"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Verander oudio-instellings."</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Affekteer battery"</string>
@@ -561,7 +561,7 @@
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Laat die program toe om die USB-berging se inhoud te lees, wat foto\'s en media kan insluit."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Laat die program toe om die SD-kaart se inhoud te lees, wat foto\'s en media kan insluit."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"verander of vee die inhoud van jou USB-berging uit"</string>
- <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"Verander of skrap die inhoud van jou SD-kaart"</string>
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"Verander of vee die inhoud van jou SD-kaart uit"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Laat die program toe om die USB-geheue te skryf."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Laat die program toe om na die SD-kaart te skryf."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"verander/vee uit interne mediabergingsinhoud"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 0da38aa..72132dd 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1311,7 +1311,6 @@
<string name="sending" msgid="3245653681008218030">"Enviando..."</string>
<string name="launchBrowserDefault" msgid="2057951947297614725">"¿Deseas iniciar el navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
- <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
- <skip />
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
<string name="activity_resolver_use_once" msgid="405646673463328329">"Solo una vez"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 3c705ec..f5132c1 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1311,7 +1311,6 @@
<string name="sending" msgid="3245653681008218030">"Siunčiama…"</string>
<string name="launchBrowserDefault" msgid="2057951947297614725">"Paleisti naršyklę?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Priimti skambutį?"</string>
- <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
- <skip />
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"Visada"</string>
<string name="activity_resolver_use_once" msgid="405646673463328329">"Tik kartą"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 0b96365..e6c8d99 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1311,7 +1311,6 @@
<string name="sending" msgid="3245653681008218030">"Notiek sūtīšana…"</string>
<string name="launchBrowserDefault" msgid="2057951947297614725">"Vai palaist pārlūkprogrammu?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vai atbildēt uz zvanu?"</string>
- <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
- <skip />
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vienmēr"</string>
<string name="activity_resolver_use_once" msgid="405646673463328329">"Tikai vienreiz"</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 47aa00a..1ab7002 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -177,7 +177,7 @@
<string name="permgroupdesc_network" msgid="4478299413241861987">"Akses pelbagai ciri rangkaian."</string>
<string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
<string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Akses peranti dan rangkaian melalui Bluetooth."</string>
- <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Rangkaian jarak-pendek"</string>
+ <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Rangkaian jarak-dekat"</string>
<string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Akses peranti melalui rangkaian jarak dekat seperti NFC."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Tetapan Audio"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Tukar tetapan audio."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 4bb3b2f..e7a809c 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -178,7 +178,7 @@
<string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
<string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Aceder a dispositivos e redes através de Bluetooth."</string>
<string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Redes de Curto Alcance"</string>
- <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Aceder a dispositivos através de redes de curto alcance como NFC."</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Aceder a dispositivos através de redes de curto alcance tal como a NFC."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Definições de Áudio"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Alterar as definições de áudio."</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Afetar a Bateria"</string>
@@ -1311,7 +1311,6 @@
<string name="sending" msgid="3245653681008218030">"A enviar..."</string>
<string name="launchBrowserDefault" msgid="2057951947297614725">"Iniciar Navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
- <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
- <skip />
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
<string name="activity_resolver_use_once" msgid="405646673463328329">"Só Uma Vez"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 4236d50..84ce4bb 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1104,7 +1104,7 @@
<string name="dlg_error_title" msgid="7323658469626514207">"Falha na operação do USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
<string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como um dispositivo de mídia"</string>
- <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectadas como uma câmera"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como câmera"</string>
<string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectados como um instalador"</string>
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a um acessório USB"</string>
<string name="usb_notification_message" msgid="2290859399983720271">"Toque para obter outras opções USB."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index e943dda..3b416fe 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -175,28 +175,20 @@
<string name="permgroupdesc_location" msgid="5704679763124170100">"Надгледајте своју физичку локацију."</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Комуникација преко мреже"</string>
<string name="permgroupdesc_network" msgid="4478299413241861987">"Приступајте разним функцијама мреже."</string>
- <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
- <skip />
- <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
- <skip />
- <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
- <skip />
- <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
- <skip />
+ <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
+ <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Приступање уређајима и мрежама преко Bluetooth-а."</string>
+ <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Мреже кратког домета"</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Приступање уређајима преко мрежа кратког домета, као што је NFC."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Аудио подешавања"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Промена аудио подешавања."</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Утицај на батерију"</string>
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Коришћење функција које могу брзо да истроше батерију."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"Директан приступ календару и догађајима."</string>
- <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
- <skip />
- <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
- <skip />
- <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
- <skip />
- <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
- <skip />
+ <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Читање речника корисника"</string>
+ <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Читање речи у речнику корисника."</string>
+ <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Уписивање у речник корисника"</string>
+ <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Додавање речи у речник корисника."</string>
<string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Обележивачи и историја"</string>
<string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Директан приступ обележивачима и историји прегледача."</string>
<string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"Аларм"</string>
@@ -569,8 +561,7 @@
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Дозвољава апликацији читање садржаја USB меморије, што могу да буду слике и медиа датотеке."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Дозвољава апликацији да чита садржај SD картице, који може да обухвата слике и медиа датотеке."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"измена или брисање садржаја USB меморије"</string>
- <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
- <skip />
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"мењање или брисање садржаја SD картице"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Дозвољава апликацији да уписује податке на USB меморију."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дозвољава апликацији да уписује податке на SD картицу."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"измена/брисање интерне меморије медија"</string>
@@ -1090,8 +1081,7 @@
<string name="date_time_set" msgid="5777075614321087758">"Подеси"</string>
<string name="date_time_done" msgid="2507683751759308828">"Готово"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"НОВО: "</font></string>
- <!-- no translation found for perms_description_app (5139836143293299417) -->
- <skip />
+ <string name="perms_description_app" msgid="5139836143293299417">"Омогућава <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="no_permissions" msgid="7283357728219338112">"Није потребна ниједна дозвола"</string>
<string name="usb_storage_activity_title" msgid="4465055157209648641">"USB великог капацитета"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB је повезан"</string>
@@ -1322,6 +1312,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Желите ли да покренете прегледач?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Желите ли да прихватите позив?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Увек"</string>
- <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="405646673463328329">"Само једном"</string>
</resources>
diff --git a/core/res/res/values-sw720dp-land/arrays.xml b/core/res/res/values-sw720dp-land/arrays.xml
new file mode 100644
index 0000000..d845875
--- /dev/null
+++ b/core/res/res/values-sw720dp-land/arrays.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <array name="lockscreen_chevron_drawables">
+ <item>@drawable/ic_lockscreen_chevron_right</item>
+ <item>@null</item>
+ <item>@null</item>
+ <item>@null</item>
+ </array>
+
+</resources>
diff --git a/core/res/res/values-sw720dp-port/arrays.xml b/core/res/res/values-sw720dp-port/arrays.xml
new file mode 100644
index 0000000..d845875
--- /dev/null
+++ b/core/res/res/values-sw720dp-port/arrays.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <array name="lockscreen_chevron_drawables">
+ <item>@drawable/ic_lockscreen_chevron_right</item>
+ <item>@null</item>
+ <item>@null</item>
+ <item>@null</item>
+ </array>
+
+</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 46c58e3..17dcf64 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -175,28 +175,20 @@
<string name="permgroupdesc_location" msgid="5704679763124170100">"ตรวจดูตำแหน่งทางกายภาพของคุณ"</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"การสื่อสารของเครือข่าย"</string>
<string name="permgroupdesc_network" msgid="4478299413241861987">"เข้าถึงคุณลักษณะเครือข่ายต่างๆ"</string>
- <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
- <skip />
- <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
- <skip />
- <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
- <skip />
- <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
- <skip />
+ <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"บลูทูธ"</string>
+ <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"เข้าถึงอุปกรณ์และเครือข่ายผ่านบลูทูธ"</string>
+ <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"เครือข่ายระยะใกล้"</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"เข้าถึงอุปกรณ์ผ่านเครือข่ายระยะใกล้ เช่น NFC"</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"การตั้งค่าเสียง"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"เปลี่ยนการตั้งค่าเสียง"</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"มีผลต่อแบตเตอรี่"</string>
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"ใช้คุณลักษณะที่ทำให้พลังงานแบตเตอรี่ลดลงอย่างรวดเร็ว"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ปฏิทิน"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"เข้าถึงปฏิทินและกิจกรรมโดยตรง"</string>
- <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
- <skip />
- <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
- <skip />
- <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
- <skip />
- <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
- <skip />
+ <string name="permgrouplab_dictionary" msgid="4148597128843641379">"อ่านพจนานุกรมผู้ใช้"</string>
+ <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"อ่านคำในพจนานุกรมผู้ใช้"</string>
+ <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"เขียนพจนานุกรมผู้ใช้"</string>
+ <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"เพิ่มคำลงในพจนานุกรมผู้ใช้"</string>
<string name="permgrouplab_bookmarks" msgid="1949519673103968229">"บุ๊กมาร์กและประวัติ"</string>
<string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"เข้าถึงบุ๊กมาร์กและประวัติของเบราว์เซอร์โดยตรง"</string>
<string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"เตือน"</string>
@@ -569,8 +561,7 @@
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"อนุญาตให้แอปอ่านเนื้อหาในที่จัดเก็บข้อมูล USB ซึ่งอาจรวมไปถึงรูปภาพและสื่อ"</string>
<string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"อนุญาตให้แอปอ่านเนื้อหาในการ์ด SD ซึ่งอาจรวมไปถึงรูปภาพและสื่อ"</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"แก้ไขหรือลบเนื้อหาใน USB"</string>
- <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
- <skip />
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"แก้ไขหรือลบเนื้อหาในการ์ด SD ของคุณ"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"อนุญาตให้แอปฯ เขียนลงใน USB"</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"อนุญาตให้แอปพลิเคชันเขียนลงบนการ์ด SD"</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"แก้/ลบเนื้อหาข้อมูลสื่อภายใน"</string>
@@ -1090,8 +1081,7 @@
<string name="date_time_set" msgid="5777075614321087758">"ตั้งค่า"</string>
<string name="date_time_done" msgid="2507683751759308828">"เสร็จสิ้น"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"ใหม่: "</font></string>
- <!-- no translation found for perms_description_app (5139836143293299417) -->
- <skip />
+ <string name="perms_description_app" msgid="5139836143293299417">"โดย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="no_permissions" msgid="7283357728219338112">"ไม่ต้องการการอนุญาต"</string>
<string name="usb_storage_activity_title" msgid="4465055157209648641">"ที่จัดเก็บข้อมูลจำนวนมากแบบ USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"เชื่อมต่อ USB แล้ว"</string>
@@ -1321,8 +1311,6 @@
<string name="sending" msgid="3245653681008218030">"กำลังส่ง…"</string>
<string name="launchBrowserDefault" msgid="2057951947297614725">"เปิดเบราว์เซอร์หรือไม่"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"รับสายหรือไม่"</string>
- <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
- <skip />
- <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
- <skip />
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"ทุกครั้ง"</string>
+ <string name="activity_resolver_use_once" msgid="405646673463328329">"เพียงแค่ครั้งเดียว"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 9aa2df3..9222823 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -175,28 +175,20 @@
<string name="permgroupdesc_location" msgid="5704679763124170100">"Fiziksel konumunuzu izleme."</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Ağ iletişimi"</string>
<string name="permgroupdesc_network" msgid="4478299413241861987">"Çeşitli ağ özelliklerine erişme."</string>
- <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
- <skip />
- <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
- <skip />
- <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
- <skip />
- <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
- <skip />
+ <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
+ <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Cihazlara ve ağlara Bluetooth ile eriş."</string>
+ <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Kısa Mesafeli Ağlar"</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Cihazlara NFC gibi kısa mesafeli ağları kullanarak eriş."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Ses Ayarları"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Ses ayarlarını değiştirme."</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Pili Etkileyenler"</string>
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Pili çok çabuk tüketebilen özellikleri kullanma."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Takvim"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"Takvime ve etkinliklere doğrudan erişim."</string>
- <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
- <skip />
- <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
- <skip />
- <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
- <skip />
- <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
- <skip />
+ <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Kullanıcı Sözlüğünü Oku"</string>
+ <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Kelimeleri kullanıcı sözlüğünde oku."</string>
+ <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Kullanıcı Sözlüğüne Yaz"</string>
+ <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Kelimeleri kullanıcı sözlüğüne ekle."</string>
<string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Yer İşaretleri ve Geçmiş"</string>
<string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Yer işaretlerine ve tarayıcı geçmişine doğrudan erişim."</string>
<string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"Alarm"</string>
@@ -569,8 +561,7 @@
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Uygulamaya USB depolamanın içeriğini okuma izni verir. Bu izin fotoğrafları ve medyayı da içerebilir."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Uygulamaya SD kartın içeriğini okuma izni verir. Bu izin fotoğrafları ve medyayı da içerebilir."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"USB depolamamın içeriğini değiştir veya sil"</string>
- <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
- <skip />
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"SD kartın içeriğini değiştir veya sil"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Uygulamaya USB depolama birimine yazma izni verir."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Uygulamaya, SD karta yazma izni verir."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"dahili medya depolama birimi içeriğini değiştir/sil"</string>
@@ -1090,8 +1081,7 @@
<string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string>
<string name="date_time_done" msgid="2507683751759308828">"Tamamlandı"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"YENİ: "</font></string>
- <!-- no translation found for perms_description_app (5139836143293299417) -->
- <skip />
+ <string name="perms_description_app" msgid="5139836143293299417">"Sağlayan: <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="no_permissions" msgid="7283357728219338112">"İzin gerektirmez"</string>
<string name="usb_storage_activity_title" msgid="4465055157209648641">"USB yığın depolama"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB bağlandı"</string>
@@ -1321,8 +1311,6 @@
<string name="sending" msgid="3245653681008218030">"Gönderiliyor…"</string>
<string name="launchBrowserDefault" msgid="2057951947297614725">"Tarayıcı Başlatılsın mı?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Çağrı kabul edilsin mi?"</string>
- <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
- <skip />
- <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
- <skip />
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"Her zaman"</string>
+ <string name="activity_resolver_use_once" msgid="405646673463328329">"Sadece Bir Defa"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 148713237..542f048 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1311,7 +1311,6 @@
<string name="sending" msgid="3245653681008218030">"Đang gửi…"</string>
<string name="launchBrowserDefault" msgid="2057951947297614725">"Khởi chạy trình duyệt?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Chấp nhận cuộc gọi?"</string>
- <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
- <skip />
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"Luôn bật"</string>
<string name="activity_resolver_use_once" msgid="405646673463328329">"Chỉ một lần"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index dce0525..0c9717f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -185,7 +185,7 @@
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Sebenzisa izici ezingakhipha ngokushesha ibhethri."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Ikhalenda"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"Ukufinyelela okuqondile kukhalenda nezehlakalo."</string>
- <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Funda isichzamazwi somsebenzisi"</string>
+ <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Funda isichazamazwi somsebenzisi"</string>
<string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Funda amagama kusichazamazwi somsebenzisi."</string>
<string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Bhala isichazamazwi somsebenzisi"</string>
<string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Engeza amagama kusichazamazwi somsebenzisi."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5fa7b7e..98e7769 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -512,7 +512,6 @@
0 - Nothing
1 - Recent apps dialog
2 - Recent apps view in SystemUI
- 3 - Voice search
This needs to match the constants in
policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
-->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 687a00b..4511201 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -846,6 +846,12 @@
interface of an input method. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindAccessibilityService">bind to an accessibility service</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindAccessibilityService">Allows the holder to bind to the top-level
+ interface of an accessibility service. Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindTextService">bind to a text service</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindTextService">Allows the holder to bind to the top-level
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 2b34dab..a90dab8 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -239,22 +239,25 @@
</style>
<!-- Notification content styles -->
<style name="TextAppearance.StatusBar.EventContent">
- <item name="android:textColor">?android:attr/textColorSecondary</item>
- <item name="android:textSize">12sp</item>
+ <item name="android:textColor">#808080</item>
+ <item name="android:textSize">14dp</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Title">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:textSize">16sp</item>
+ <item name="android:textColor">#ffffff</item>
+ <item name="android:fontFamily">sans-serif-light</item>
+ <item name="android:textSize">18dp</item>
<item name="android:textStyle">bold</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Line2">
- <item name="android:textSize">13sp</item>
+ <!-- inherit all -->
</style>
<style name="TextAppearance.StatusBar.EventContent.Info">
- <!-- inherit all -->
+ <item name="android:textSize">12sp</item>
+ <item name="android:textColor">#666666</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Time">
- <!-- inherit all -->
+ <item name="android:textSize">12sp</item>
+ <item name="android:textColor">#666666</item>
</style>
<style name="TextAppearance.Small.CalendarViewWeekDayView">
@@ -631,6 +634,7 @@
<style name="Widget.WebView">
<item name="android:focusable">true</item>
+ <item name="android:focusableInTouchMode">true</item>
<item name="android:scrollbars">horizontal|vertical</item>
</style>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index cadc895..dcd1bab 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1039,7 +1039,8 @@
</intent-filter>
</activity>
- <service android:name="android.webkit.AccessibilityInjectorTest$MockAccessibilityService">
+ <service android:name="android.webkit.AccessibilityInjectorTest$MockAccessibilityService"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
diff --git a/core/tests/coretests/src/android/net/SSLTest.java b/core/tests/coretests/src/android/net/SSLTest.java
index c573498..27b699d 100644
--- a/core/tests/coretests/src/android/net/SSLTest.java
+++ b/core/tests/coretests/src/android/net/SSLTest.java
@@ -59,6 +59,14 @@
new byte[] { 'h', 't', 't', 'p', '/', '1', '.', '1' })));
}
+ public void testStringsToNpnBytesEmptyArray() {
+ try {
+ SSLCertificateSocketFactory.toNpnProtocolsList();
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
public void testStringsToNpnBytesEmptyByteArray() {
try {
SSLCertificateSocketFactory.toNpnProtocolsList(new byte[0]);
@@ -67,11 +75,6 @@
}
}
- public void testStringsToNpnBytesEmptyArray() {
- byte[] expected = {};
- assertTrue(Arrays.equals(expected, SSLCertificateSocketFactory.toNpnProtocolsList()));
- }
-
public void testStringsToNpnBytesOversizedInput() {
try {
SSLCertificateSocketFactory.toNpnProtocolsList(new byte[256]);
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index c41f971..dd9b554 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -180,6 +180,9 @@
trivial getter. This is true in Froyo, but will improve in the future when
the JIT inlines getter methods.</p>
+<p>Note that if you're using ProGuard, you can have the best
+of both worlds because ProGuard can inline accessors for you.</p>
+
<a name="use_final" id="use_final"></a>
<h2>Use Static Final For Constants</h2>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index ef5da5b..16cfa92 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2000,6 +2000,37 @@
}
/**
+ * @hide
+ * Used internally by telephony package to register an intent receiver for ACTION_MEDIA_BUTTON.
+ * @param eventReceiver the component that will receive the media button key events,
+ * no-op if eventReceiver is null
+ */
+ public void registerMediaButtonEventReceiverForCalls(ComponentName eventReceiver) {
+ if (eventReceiver == null) {
+ return;
+ }
+ IAudioService service = getService();
+ try {
+ // eventReceiver != null
+ service.registerMediaButtonEventReceiverForCalls(eventReceiver);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in registerMediaButtonEventReceiverForCalls", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void unregisterMediaButtonEventReceiverForCalls() {
+ IAudioService service = getService();
+ try {
+ service.unregisterMediaButtonEventReceiverForCalls();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in unregisterMediaButtonEventReceiverForCalls", e);
+ }
+ }
+
+ /**
* Unregister the receiver of MEDIA_BUTTON intents.
* @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
* that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 8da7d0f..d165b5e 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -3625,12 +3625,14 @@
Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
return;
}
- // event filtering based on audio mode
+ // event filtering for telephony
synchronized(mRingingLock) {
- if (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL) ||
- (getMode() == AudioSystem.MODE_IN_COMMUNICATION) ||
- (getMode() == AudioSystem.MODE_RINGTONE) ) {
- return;
+ synchronized(mRCStack) {
+ if ((mMediaReceiverForCalls != null) &&
+ (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) {
+ dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
+ return;
+ }
}
}
// event filtering based on voice-based interactions
@@ -3642,6 +3644,25 @@
}
/**
+ * Handles the dispatching of the media button events to the telephony package.
+ * Precondition: mMediaReceiverForCalls != null
+ * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
+ * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+ * is dispatched.
+ */
+ private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
+ Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+ keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
+ if (needWakeLock) {
+ mMediaEventWakeLock.acquire();
+ keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
+ }
+ mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone,
+ mAudioHandler, Activity.RESULT_OK, null, null);
+ }
+
+ /**
* Handles the dispatching of the media button events to one of the registered listeners,
* or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
* @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
@@ -4028,6 +4049,12 @@
private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
/**
+ * The component the telephony package can register so telephony calls have priority to
+ * handle media button events
+ */
+ private ComponentName mMediaReceiverForCalls = null;
+
+ /**
* Helper function:
* Display in the log the current entries in the remote control focus stack
*/
@@ -4381,6 +4408,35 @@
}
/**
+ * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
+ * precondition: c != null
+ */
+ public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
+ if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
+ != PackageManager.PERMISSION_GRANTED) {
+ Log.e(TAG, "Invalid permissions to register media button receiver for calls");
+ return;
+ }
+ synchronized(mRCStack) {
+ mMediaReceiverForCalls = c;
+ }
+ }
+
+ /**
+ * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
+ */
+ public void unregisterMediaButtonEventReceiverForCalls() {
+ if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
+ != PackageManager.PERMISSION_GRANTED) {
+ Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
+ return;
+ }
+ synchronized(mRCStack) {
+ mMediaReceiverForCalls = null;
+ }
+ }
+
+ /**
* see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
* Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
* without modifying the RC stack, but while still causing the display to refresh (will
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 48f091c..6753ad3 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -109,6 +109,9 @@
oneway void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c);
oneway void unregisterMediaButtonIntent(in PendingIntent pi, in ComponentName c);
+ oneway void registerMediaButtonEventReceiverForCalls(in ComponentName c);
+ oneway void unregisterMediaButtonEventReceiverForCalls();
+
oneway void registerRemoteControlClient(in PendingIntent mediaIntent,
in IRemoteControlClient rcClient, in String callingPackageName);
oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 821a251b..987c0ac 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1623,7 +1623,7 @@
if (line.startsWith("File")) {
int equals = line.indexOf('=');
if (equals > 0) {
- cachePlaylistEntry(line, playListDirectory);
+ cachePlaylistEntry(line.substring(equals + 1), playListDirectory);
}
}
line = reader.readLine();
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index d1cf8b5..040d2ab 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -47,20 +47,23 @@
$(TOP)/frameworks/native/include/media/openmax
LOCAL_SHARED_LIBRARIES := \
+ libandroid_runtime \
+ libaudioflinger \
libaudioutils \
+ libbinder \
libcutils \
libdl \
- libutils \
- libandroid_runtime \
- libnativehelper \
+ libgui \
libmedia \
- libaudioflinger \
- libbinder \
+ libnativehelper \
libstagefright \
libstagefright_foundation \
libstagefright_omx \
- libgui \
- libvideoeditorplayer
+ libutils \
+ libvideoeditor_core \
+ libvideoeditor_osal \
+ libvideoeditor_videofilters \
+ libvideoeditorplayer \
LOCAL_CFLAGS += \
@@ -72,15 +75,6 @@
-DUSE_STAGEFRIGHT_READERS \
-DUSE_STAGEFRIGHT_3GPP_READER
-LOCAL_STATIC_LIBRARIES := \
- libvideoeditor_core \
- libstagefright_color_conversion \
- libvideoeditor_3gpwriter \
- libvideoeditor_mcs \
- libvideoeditor_videofilters \
- libvideoeditor_stagefrightshells \
- libvideoeditor_osal
-
LOCAL_MODULE:= libvideoeditor_jni
LOCAL_MODULE_TAGS := optional
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 50aaa9a..0165977 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -34,6 +34,7 @@
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
+import java.io.CharArrayReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
@@ -45,7 +46,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.zip.CRC32;
@@ -55,7 +60,7 @@
*/
public class SettingsBackupAgent extends BackupAgentHelper {
private static final boolean DEBUG = false;
- private static final boolean DEBUG_BACKUP = DEBUG || true;
+ private static final boolean DEBUG_BACKUP = DEBUG || false;
private static final String KEY_SYSTEM = "system";
private static final String KEY_SECURE = "secure";
@@ -111,6 +116,130 @@
private WifiManager mWfm;
private static String mWifiConfigFile;
+ // Class for capturing a network definition from the wifi supplicant config file
+ static class Network {
+ String ssid = ""; // equals() and hashCode() need these to be non-null
+ String key_mgmt = "";
+ final ArrayList<String> rawLines = new ArrayList<String>();
+
+ public static Network readFromStream(BufferedReader in) {
+ final Network n = new Network();
+ String line;
+ try {
+ while (in.ready()) {
+ line = in.readLine();
+ if (line == null || line.startsWith("}")) {
+ break;
+ }
+ n.rememberLine(line);
+ }
+ } catch (IOException e) {
+ return null;
+ }
+ return n;
+ }
+
+ void rememberLine(String line) {
+ // can't rely on particular whitespace patterns so strip leading/trailing
+ line = line.trim();
+ if (line.isEmpty()) return; // only whitespace; drop the line
+ rawLines.add(line);
+
+ // remember the ssid and key_mgmt lines for duplicate culling
+ if (line.startsWith("ssid")) {
+ ssid = line;
+ } else if (line.startsWith("key_mgmt")) {
+ key_mgmt = line;
+ }
+ }
+
+ public void write(Writer w) throws IOException {
+ w.write("\nnetwork={\n");
+ for (String line : rawLines) {
+ w.write("\t" + line + "\n");
+ }
+ w.write("}\n");
+ }
+
+ public void dump() {
+ Log.v(TAG, "network={");
+ for (String line : rawLines) {
+ Log.v(TAG, " " + line);
+ }
+ Log.v(TAG, "}");
+ }
+
+ // Same approach as Pair.equals() and Pair.hashCode()
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof Network)) return false;
+ final Network other;
+ try {
+ other = (Network) o;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ return ssid.equals(other.ssid) && key_mgmt.equals(other.key_mgmt);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + ssid.hashCode();
+ result = 31 * result + key_mgmt.hashCode();
+ return result;
+ }
+ }
+
+ // Ingest multiple wifi config file fragments, looking for network={} blocks
+ // and eliminating duplicates
+ class WifiNetworkSettings {
+ // One for fast lookup, one for maintaining ordering
+ final HashSet<Network> mKnownNetworks = new HashSet<Network>();
+ final ArrayList<Network> mNetworks = new ArrayList<Network>(8);
+
+ public void readNetworks(BufferedReader in) {
+ try {
+ String line;
+ while (in.ready()) {
+ line = in.readLine();
+ if (line != null) {
+ // Parse out 'network=' decls so we can ignore duplicates
+ if (line.startsWith("network")) {
+ Network net = Network.readFromStream(in);
+ if (! mKnownNetworks.contains(net)) {
+ if (DEBUG_BACKUP) {
+ Log.v(TAG, "Adding " + net.ssid + " / " + net.key_mgmt);
+ }
+ mKnownNetworks.add(net);
+ mNetworks.add(net);
+ } else {
+ if (DEBUG_BACKUP) {
+ Log.v(TAG, "Dupe; skipped " + net.ssid + " / " + net.key_mgmt);
+ }
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ // whatever happened, we're done now
+ }
+ }
+
+ public void write(Writer w) throws IOException {
+ for (Network net : mNetworks) {
+ net.write(w);
+ }
+ }
+
+ public void dump() {
+ for (Network net : mNetworks) {
+ net.dump();
+ }
+ }
+ }
+
@Override
public void onCreate() {
if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
@@ -622,29 +751,51 @@
private void restoreWifiSupplicant(String filename, byte[] bytes, int size) {
try {
- File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
- if (supplicantFile.exists()) supplicantFile.delete();
- copyWifiSupplicantTemplate();
+ WifiNetworkSettings supplicantImage = new WifiNetworkSettings();
- OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
- os.write("\n".getBytes());
- os.write(bytes, 0, size);
- os.close();
+ File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
+ if (supplicantFile.exists()) {
+ // Retain the existing APs; we'll append the restored ones to them
+ BufferedReader in = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT));
+ supplicantImage.readNetworks(in);
+ in.close();
+
+ supplicantFile.delete();
+ }
+
+ // Incorporate the restore AP information
+ if (size > 0) {
+ char[] restoredAsBytes = new char[size];
+ for (int i = 0; i < size; i++) restoredAsBytes[i] = (char) bytes[i];
+ BufferedReader in = new BufferedReader(new CharArrayReader(restoredAsBytes));
+ supplicantImage.readNetworks(in);
+
+ if (DEBUG_BACKUP) {
+ Log.v(TAG, "Final AP list:");
+ supplicantImage.dump();
+ }
+ }
+
+ // Install the correct default template
+ BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
+ copyWifiSupplicantTemplate(bw);
+
+ // Write the restored supplicant config and we're done
+ supplicantImage.write(bw);
+ bw.close();
} catch (IOException ioe) {
Log.w(TAG, "Couldn't restore " + filename);
}
}
- private void copyWifiSupplicantTemplate() {
+ private void copyWifiSupplicantTemplate(BufferedWriter bw) {
try {
BufferedReader br = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT_TEMPLATE));
- BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
char[] temp = new char[1024];
int size;
while ((size = br.read(temp)) > 0) {
bw.write(temp, 0, size);
}
- bw.close();
br.close();
} catch (IOException ioe) {
Log.w(TAG, "Couldn't copy wpa_supplicant file");
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
index daf18c7..d9ec745 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..117cf19
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
index 5292998..2cebe85 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..7c60bea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..9e6323c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..09b35b3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..2220c73
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..ea987f1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..21db6a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..5e8baa4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
index 3e7fefd..90b8c84 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..5881402
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/navbar_search_outerring.xml b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
index 37b6c1c..0dd081d 100644
--- a/packages/SystemUI/res/drawable/navbar_search_outerring.xml
+++ b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
@@ -19,5 +19,5 @@
<size android:height="@dimen/navbar_search_outerring_diameter"
android:width="@dimen/navbar_search_outerring_diameter" />
<solid android:color="#00000000" />
- <stroke android:color="#1affffff" android:width="2dp" />
+ <stroke android:color="#40ffffff" android:width="2dp" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml b/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
index b9af3a9..f93dd33 100644
--- a/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
@@ -26,15 +26,16 @@
android:fitsSystemWindows="true"
>
+ <include layout="@layout/status_bar"
+ android:layout_width="match_parent"
+ android:layout_height="@*android:dimen/status_bar_height"
+ />
+
<include layout="@layout/status_bar_expanded"
android:layout_width="@dimen/notification_panel_width"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal|top"
- />
-
- <include layout="@layout/status_bar"
- android:layout_width="match_parent"
- android:layout_height="@*android:dimen/status_bar_height"
+ android:visibility="invisible"
/>
</com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index b905db3..d41040d 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -69,7 +69,7 @@
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_home"
systemui:keyCode="3"
- systemui:keyRepeat="true"
+ systemui:keyRepeat="false"
android:layout_weight="0"
systemui:glowBackground="@drawable/ic_sysbar_highlight"
android:contentDescription="@string/accessibility_home"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 4cff67b..406ed25 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -23,34 +23,39 @@
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:id="@+id/notification_panel"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
+ android:layout_height="match_parent"
android:background="@drawable/notification_panel_bg"
android:paddingTop="@dimen/notification_panel_padding_top"
android:layout_marginLeft="@dimen/notification_panel_margin_left"
>
- <include layout="@layout/status_bar_expanded_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
-
- <ScrollView
- android:id="@+id/scroll"
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:fadingEdge="none"
- android:overScrollMode="ifContentScrolls"
- android:layout_marginTop="@dimen/notification_panel_header_height"
android:layout_marginBottom="@dimen/close_handle_underlap"
>
- <com.android.systemui.statusbar.policy.NotificationRowLayout
- android:id="@+id/latestItems"
+
+ <include layout="@layout/status_bar_expanded_header"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- systemui:rowHeight="@dimen/notification_row_min_height"
+ android:layout_height="48dp"
/>
- </ScrollView>
+
+ <ScrollView
+ android:id="@+id/scroll"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fadingEdge="none"
+ android:overScrollMode="ifContentScrolls"
+ android:layout_marginTop="@dimen/notification_panel_header_height"
+ >
+ <com.android.systemui.statusbar.policy.NotificationRowLayout
+ android:id="@+id/latestItems"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ systemui:rowHeight="@dimen/notification_row_min_height"
+ />
+ </ScrollView>
+ </FrameLayout>
<com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
android:layout_width="match_parent"
@@ -67,5 +72,4 @@
/>
</com.android.systemui.statusbar.phone.CloseDragHandle>
-
</FrameLayout><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 6c31ff4..b85686f 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -26,14 +26,15 @@
android:fitsSystemWindows="true"
>
- <include layout="@layout/status_bar_expanded"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
-
<include layout="@layout/status_bar"
android:layout_width="match_parent"
android:layout_height="@*android:dimen/status_bar_height"
/>
+ <include layout="@layout/status_bar_expanded"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ />
+
</com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b4e0d8a..06a9395 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -144,10 +144,7 @@
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Información de la aplicación"</string>
<string name="notifications_off_title" msgid="8936620513608443224">"Notificaciones desactivadas"</string>
<string name="notifications_off_text" msgid="2529001315769385273">"Toca aquí para volver a activar las notificaciones."</string>
- <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
- <skip />
+ <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla rotará automáticamente."</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index a242640..018b5e5 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -142,10 +142,7 @@
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Programos informacija"</string>
<string name="notifications_off_title" msgid="8936620513608443224">"Pranešimai išjungti"</string>
<string name="notifications_off_text" msgid="2529001315769385273">"Jei norite vėl įjungti pranešimus, palieskite čia."</string>
- <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
- <skip />
+ <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekranas bus sukamas automatiškai."</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Užrakintas ekranas yra horizontalios orientacijos."</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Užrakintas ekranas yra vertikalios orientacijos."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 3c2e193..e708804 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -142,10 +142,7 @@
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informācija par lietotni"</string>
<string name="notifications_off_title" msgid="8936620513608443224">"Paziņojumi ir izslēgti"</string>
<string name="notifications_off_text" msgid="2529001315769385273">"Pieskarieties šeit, lai atkal ieslēgtu paziņojumus."</string>
- <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
- <skip />
+ <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekrāns tiks pagriezts automātiski."</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekrāns tagad ir bloķēts ainavas orientācijā."</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekrāns tagad ir bloķēts portreta orientācijā."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 77ed068..d08c529 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -142,10 +142,7 @@
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informações da aplicação"</string>
<string name="notifications_off_title" msgid="8936620513608443224">"Notificações desativadas"</string>
<string name="notifications_off_text" msgid="2529001315769385273">"Toque aqui para voltar a ativar as notificações."</string>
- <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
- <skip />
+ <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"O ecrã será rodado automaticamente."</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"O ecrã está bloqueado na orientação horizontal."</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"O ecrã está bloqueado na orientação vertical."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5f523a2..fd41e02 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -140,10 +140,8 @@
<string name="accessibility_clear_all" msgid="5235938559247164925">"Обриши сва обавештења."</string>
<string name="dreams_dock_launcher" msgid="3541196417659166245">"Активирање чувара екрана"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Информације о апликацији"</string>
- <!-- no translation found for notifications_off_title (8936620513608443224) -->
- <skip />
- <!-- no translation found for notifications_off_text (2529001315769385273) -->
- <skip />
+ <string name="notifications_off_title" msgid="8936620513608443224">"Обавештења су искључена"</string>
+ <string name="notifications_off_text" msgid="2529001315769385273">"Додирните овде да бисте поново укључили обавештења."</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран ће се аутоматски ротирати."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екран је закључан у хоризонталном положају."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екран је закључан у вертикалном положају."</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 07d55f1..be59075 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -33,9 +33,6 @@
<!-- Height of search panel including navigation bar height -->
<dimen name="navbar_search_panel_height">300dip</dimen>
- <!-- Extra space above the clock in the panel; on this device, zero -->
- <dimen name="notification_panel_header_padding_top">0dp</dimen>
-
<!-- Size of application thumbnail -->
<dimen name="status_bar_recents_thumbnail_width">200dp</dimen>
<dimen name="status_bar_recents_thumbnail_height">177dp</dimen>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index dbb8d91..70f0b9b 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -140,14 +140,9 @@
<string name="accessibility_clear_all" msgid="5235938559247164925">"ล้างการแจ้งเตือนทั้งหมด"</string>
<string name="dreams_dock_launcher" msgid="3541196417659166245">"เปิดโปรแกรมรักษาหน้าจอ"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"ข้อมูลแอป"</string>
- <!-- no translation found for notifications_off_title (8936620513608443224) -->
- <skip />
- <!-- no translation found for notifications_off_text (2529001315769385273) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
- <skip />
+ <string name="notifications_off_title" msgid="8936620513608443224">"การแจ้งเตือนปิดอยู่"</string>
+ <string name="notifications_off_text" msgid="2529001315769385273">"แตะที่นี่เพื่อเปิดการแจ้งเตือนอีกครั้ง"</string>
+ <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"หน้าจอจะหมุนโดยอัตโนมัติ"</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ขณะนี้หน้าจอถูกล็อกให้วางในแนวนอน"</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ขณะนี้หน้าจอถูกล็อกให้วางในแนวตั้ง"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d0f08fc..9bf8f76 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -140,14 +140,9 @@
<string name="accessibility_clear_all" msgid="5235938559247164925">"Tüm bildirimleri temizle"</string>
<string name="dreams_dock_launcher" msgid="3541196417659166245">"Ekran koruyucuyu etkinleştir"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Uygulama bilgileri"</string>
- <!-- no translation found for notifications_off_title (8936620513608443224) -->
- <skip />
- <!-- no translation found for notifications_off_text (2529001315769385273) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
- <skip />
+ <string name="notifications_off_title" msgid="8936620513608443224">"Bildirimler kapalı"</string>
+ <string name="notifications_off_text" msgid="2529001315769385273">"Bildirimleri tekrar açmak için buraya hafifçe vurun."</string>
+ <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran otomatik olarak dönecektir."</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran yatay yönde kilitlendi."</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran dikey yönde kilitlendi."</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 0019c7c..02d0138 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -142,10 +142,7 @@
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Thông tin về ứng dụng"</string>
<string name="notifications_off_title" msgid="8936620513608443224">"Tắt thông báo"</string>
<string name="notifications_off_text" msgid="2529001315769385273">"Chạm vào đây để bật lại thông báo."</string>
- <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
- <skip />
+ <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Màn hinh sẽ xoay tự động."</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Màn hình hiện bị khóa theo hướng ngang."</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Màn hình hiện bị khóa theo hướng dọc."</string>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9042045..b1611d1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -115,10 +115,10 @@
<dimen name="navbar_search_hit_radius">60dip</dimen>
<!-- Diameter of outer shape drawable shown in navbar search-->
- <dimen name="navbar_search_outerring_diameter">270dp</dimen>
+ <dimen name="navbar_search_outerring_diameter">340dp</dimen>
<!-- Threshold for swipe-up gesture to activate search dialog -->
- <dimen name="navbar_search_up_threshhold">20dip</dimen>
+ <dimen name="navbar_search_up_threshhold">40dip</dimen>
<!-- Height of search panel including navigation bar height -->
<dimen name="navbar_search_panel_height">230dip</dimen>
@@ -132,10 +132,10 @@
<!-- Height of the notification panel header bar -->
<dimen name="notification_panel_header_height">48dp</dimen>
- <!-- Height of the notification panel header bar -->
- <dimen name="notification_panel_padding_top">@*android:dimen/status_bar_height</dimen>
+ <!-- Extra space above the panel -->
+ <dimen name="notification_panel_padding_top">4dp</dimen>
- <!-- Extra space above the clock in the panel; half of (notification_panel_header_height - 32) -->
+ <!-- Extra space above the clock in the panel -->
<dimen name="notification_panel_header_padding_top">0dp</dimen>
<!-- Layout parameters for the notification panel -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 144760e..a23fe12 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,12 +16,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="TextAppearance.StatusBar.Title" parent="@*android:style/TextAppearance.StatusBar">
- <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:textStyle">bold</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- </style>
-
<style name="TextAppearance.StatusBar.IntruderAlert"
parent="@*android:style/TextAppearance.StatusBar">
</style>
@@ -48,7 +42,7 @@
</style>
<style name="TextAppearance.StatusBar.Date" parent="@*android:style/TextAppearance.StatusBar.Icon">
- <item name="android:textSize">16sp</item>
+ <item name="android:textSize">16dp</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@android:color/holo_blue_light</item>
</style>
@@ -57,6 +51,7 @@
<style name="TextAppearance.StatusBar.Expanded.Clock">
<item name="android:textSize">32dp</item>
+ <item name="android:fontFamily">sans-serif-light</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">#ffffff</item>
</style>
@@ -64,7 +59,7 @@
<style name="TextAppearance.StatusBar.Expanded.Date">
<item name="android:textSize">12dp</item>
<item name="android:textStyle">normal</item>
- <item name="android:textColor">#666666</item>
+ <item name="android:textColor">#cccccc</item>
<item name="android:textAllCaps">true</item>
</style>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 7a7afa7..ba3336b 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -31,7 +31,7 @@
public class ExpandHelper implements Gefingerpoken, OnClickListener {
public interface Callback {
- View getChildAtPosition(MotionEvent ev);
+ View getChildAtRawPosition(float x, float y);
View getChildAtPosition(float x, float y);
boolean canChildBeExpanded(View v);
boolean setUserExpandedChild(View v, boolean userxpanded);
@@ -62,6 +62,7 @@
private Context mContext;
private boolean mStretching;
+ private View mEventSource;
private View mCurrView;
private View mCurrViewTopGlow;
private View mCurrViewBottomGlow;
@@ -141,7 +142,19 @@
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
if (DEBUG) Log.v(TAG, "onscalebegin()");
- View v = mCallback.getChildAtPosition(detector.getFocusX(), detector.getFocusY());
+ float x = detector.getFocusX();
+ float y = detector.getFocusY();
+
+ View v = null;
+ if (mEventSource != null) {
+ int[] location = new int[2];
+ mEventSource.getLocationOnScreen(location);
+ x += (float) location[0];
+ y += (float) location[1];
+ v = mCallback.getChildAtRawPosition(x, y);
+ } else {
+ v = mCallback.getChildAtPosition(x, y);
+ }
// your fingers have to be somewhat close to the bounds of the view in question
mInitialTouchFocusY = detector.getFocusY();
@@ -189,6 +202,11 @@
}
});
}
+
+ public void setEventSource(View eventSource) {
+ mEventSource = eventSource;
+ }
+
public void setGlow(float glow) {
if (!mGlowAnimationSet.isRunning() || glow == 0f) {
if (mGlowAnimationSet.isRunning()) {
@@ -211,7 +229,6 @@
}
}
}
-
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (DEBUG) Log.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
" stretching=" + mStretching);
@@ -223,11 +240,13 @@
final int action = ev.getAction();
if (DEBUG) Log.d(TAG, "touch: act=" + (action) + " stretching=" + mStretching);
if (mStretching) {
+ if (DEBUG) Log.d(TAG, "detector ontouch");
mDetector.onTouchEvent(ev);
}
switch (action) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ if (DEBUG) Log.d(TAG, "cancel");
mStretching = false;
clearView();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index 57f15a8..6b0bb87 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -23,13 +23,15 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.speech.RecognizerIntent;
+import android.content.pm.PackageManager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnPreDrawListener;
import android.widget.FrameLayout;
import com.android.internal.widget.multiwaveview.MultiWaveView;
@@ -68,8 +70,36 @@
private SearchManager mSearchManager;
+ // This code should be the same as that used in LockScreen.java
public boolean isAssistantAvailable() {
- return mSearchManager != null && mSearchManager.getGlobalSearchActivity() != null;
+ Intent intent = getAssistIntent();
+ return intent == null ? false
+ : mContext.getPackageManager().queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
+ }
+
+ private Intent getAssistIntent() {
+ Intent intent = null;
+ SearchManager searchManager = getSearchManager();
+ if (searchManager != null) {
+ ComponentName globalSearchActivity = searchManager.getGlobalSearchActivity();
+ if (globalSearchActivity != null) {
+ intent = new Intent(Intent.ACTION_ASSIST);
+ intent.setPackage(globalSearchActivity.getPackageName());
+ } else {
+ Slog.w(TAG, "No global search activity");
+ }
+ } else {
+ Slog.w(TAG, "No SearchManager");
+ }
+ return intent;
+ }
+
+ private SearchManager getSearchManager() {
+ if (mSearchManager == null) {
+ mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+ }
+ return mSearchManager;
}
private void startAssistActivity() {
@@ -146,6 +176,14 @@
}
}
+ private OnPreDrawListener mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ mMultiWaveView.resumeAnimations();
+ return false;
+ }
+ };
+
public void show(final boolean show, boolean animate) {
if (animate) {
if (mShowing != show) {
@@ -156,16 +194,20 @@
mShowing = show;
onAnimationEnd(null);
}
- postDelayed(new Runnable() {
- public void run() {
- setVisibility(show ? View.VISIBLE : View.INVISIBLE);
- if (show) {
- setFocusable(true);
- setFocusableInTouchMode(true);
- requestFocus();
- }
+ if (show) {
+ if (getVisibility() != View.VISIBLE) {
+ setVisibility(View.VISIBLE);
+ // Don't start the animation until we've created the layer, which is done
+ // right before we are drawn
+ mMultiWaveView.suspendAnimations();
+ getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
}
- }, show ? 0 : 100);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ requestFocus();
+ } else {
+ setVisibility(View.INVISIBLE);
+ }
}
public void hide(boolean animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 6584c7d..2d65dd6 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -186,6 +186,7 @@
public void removeLongPressCallback() {
if (mWatchLongPress != null) {
mHandler.removeCallbacks(mWatchLongPress);
+ mWatchLongPress = null;
}
}
@@ -245,6 +246,7 @@
mCurrView = null;
mCurrAnimView = null;
mLongPressSent = false;
+ removeLongPressCallback();
break;
}
return mDragging;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 4b223dd..a352748 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -531,30 +531,27 @@
}
}
catch (RuntimeException e) {
- exception = e;
- }
- if (expandedOneU == null && expandedLarge == null) {
final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
- Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
+ Slog.e(TAG, "couldn't inflate view for notification " + ident, e);
return false;
- } else {
- if (expandedOneU != null) {
- SizeAdaptiveLayout.LayoutParams params =
- new SizeAdaptiveLayout.LayoutParams(expandedOneU.getLayoutParams());
- params.minHeight = minHeight;
- params.maxHeight = minHeight;
- adaptive.addView(expandedOneU, params);
- }
- if (expandedLarge != null) {
- SizeAdaptiveLayout.LayoutParams params =
- new SizeAdaptiveLayout.LayoutParams(expandedLarge.getLayoutParams());
- params.minHeight = minHeight+1;
- params.maxHeight = maxHeight;
- adaptive.addView(expandedLarge, params);
- }
- row.setDrawingCacheEnabled(true);
}
+ if (expandedOneU != null) {
+ SizeAdaptiveLayout.LayoutParams params =
+ new SizeAdaptiveLayout.LayoutParams(expandedOneU.getLayoutParams());
+ params.minHeight = rowHeight;
+ params.maxHeight = rowHeight;
+ adaptive.addView(expandedOneU, params);
+ }
+ if (expandedLarge != null) {
+ SizeAdaptiveLayout.LayoutParams params =
+ new SizeAdaptiveLayout.LayoutParams(expandedLarge.getLayoutParams());
+ params.minHeight = rowHeight+1;
+ params.maxHeight = maxHeight;
+ adaptive.addView(expandedLarge, params);
+ }
+ row.setDrawingCacheEnabled(true);
+
applyLegacyRowBackground(sbn, content);
row.setTag(R.id.expandable_tag, Boolean.valueOf(large != null));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
index 0e6dfd5..7edeaef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -63,7 +63,8 @@
break;
}
if (mDelegateView != null) {
- if (mDelegateView.getVisibility() != View.VISIBLE && event.getAction() != MotionEvent.ACTION_CANCEL) {
+ if (mDelegateView.getVisibility() != View.VISIBLE
+ && event.getAction() != MotionEvent.ACTION_CANCEL) {
final boolean isVertical = (mOrientation == Surface.ROTATION_90
|| mOrientation == Surface.ROTATION_270);
final int historySize = event.getHistorySize();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 2f02d23..1321ade 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -21,9 +21,9 @@
import android.util.Slog;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.TextView;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -31,12 +31,12 @@
// Intimately tied to the design of res/layout/signal_cluster_view.xml
public class SignalClusterView
- extends LinearLayout
+ extends LinearLayout
implements NetworkController.SignalCluster {
static final boolean DEBUG = false;
static final String TAG = "SignalClusterView";
-
+
NetworkController mNC;
private boolean mWifiVisible = false;
@@ -132,6 +132,17 @@
apply();
}
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ // Standard group layout onPopulateAccessibilityEvent() implementations
+ // ignore content description, so populate manually
+ if (mWifiVisible && mWifiGroup.getContentDescription() != null)
+ event.getText().add(mWifiGroup.getContentDescription());
+ if (mMobileVisible && mMobileGroup.getContentDescription() != null)
+ event.getText().add(mMobileGroup.getContentDescription());
+ return super.dispatchPopulateAccessibilityEvent(event);
+ }
+
// Run after each indicator change.
private void apply() {
if (mWifiGroup == null) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 2ea1827..69d2e73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -289,7 +289,7 @@
animateCollapse();
}
}
- return true;
+ return mStatusBarWindow.onTouchEvent(event);
}});
mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
@@ -301,6 +301,9 @@
return true;
}
});
+ mNotificationPanel.setSystemUiVisibility(
+ View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER
+ | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
if (!ActivityManager.isHighEndGfx(mDisplay)) {
mStatusBarWindow.setBackground(null);
@@ -336,7 +339,6 @@
mPixelFormat = PixelFormat.OPAQUE;
mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
- mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
mNotificationIcons.setOverflowIndicator(mMoreIcon);
mIcons = (LinearLayout)mStatusBarView.findViewById(R.id.icons);
mTickerView = mStatusBarView.findViewById(R.id.ticker);
@@ -884,6 +886,15 @@
flagdbg.append(((diff & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
flagdbg.append(">");
Slog.d(TAG, flagdbg.toString());
+
+ if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+ mIcons.animate().cancel();
+ if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+ mIcons.animate().alpha(0f).setStartDelay(100).setDuration(200).start();
+ } else {
+ mIcons.animate().alpha(1f).setStartDelay(0).setDuration(300).start();
+ }
+ }
if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
@@ -985,6 +996,7 @@
}
mExpandedVisible = true;
+ mNotificationPanel.setVisibility(View.VISIBLE);
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
@@ -1078,7 +1090,7 @@
}
mExpandedVisible = false;
visibilityChanged(false);
- //mNotificationPanel.setVisibility(View.GONE);
+ mNotificationPanel.setVisibility(View.INVISIBLE);
// Shrink the window to the size of the status bar only
WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 0fc5b4d..ed1b2f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -18,17 +18,39 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.TextSwitcher;
+import com.android.systemui.ExpandHelper;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NotificationRowLayout;
+
public class StatusBarWindowView extends FrameLayout
{
+ private static final String TAG = "StatusBarWindowView";
+
+ private ExpandHelper mExpandHelper;
+ private NotificationRowLayout latestItems;
+
PhoneStatusBar mService;
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
+ setMotionEventSplittingEnabled(false);
+ }
+
+ @Override
+ protected void onAttachedToWindow () {
+ super.onAttachedToWindow();
+ latestItems = (NotificationRowLayout) findViewById(R.id.latestItems);
+ int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
+ int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
+ mExpandHelper = new ExpandHelper(mContext, latestItems, minHeight, maxHeight);
+ mExpandHelper.setEventSource(this);
}
@Override
@@ -43,5 +65,25 @@
}
return super.dispatchKeyEvent(event);
}
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ MotionEvent cancellation = MotionEvent.obtain(ev);
+ cancellation.setAction(MotionEvent.ACTION_CANCEL);
+
+ boolean intercept = mExpandHelper.onInterceptTouchEvent(ev) ||
+ super.onInterceptTouchEvent(ev);
+ if (intercept) {
+ latestItems.onInterceptTouchEvent(cancellation);
+ }
+ return intercept;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ boolean handled = mExpandHelper.onTouchEvent(ev) ||
+ super.onTouchEvent(ev);
+ return handled;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index a00fab3..bb0ce16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -52,6 +52,7 @@
int mCode;
int mTouchSlop;
Drawable mGlowBG;
+ int mGlowWidth, mGlowHeight;
float mGlowAlpha = 0f, mGlowScale = 1f, mDrawingAlpha = 1f;
boolean mSupportsLongpress = true;
RectF mRect = new RectF(0f,0f,0f,0f);
@@ -89,6 +90,8 @@
mGlowBG = a.getDrawable(R.styleable.KeyButtonView_glowBackground);
if (mGlowBG != null) {
setDrawingAlpha(BUTTON_QUIESCENT_ALPHA);
+ mGlowWidth = mGlowBG.getIntrinsicWidth();
+ mGlowHeight = mGlowBG.getIntrinsicHeight();
}
a.recycle();
@@ -103,8 +106,12 @@
canvas.save();
final int w = getWidth();
final int h = getHeight();
+ final float aspect = (float)mGlowWidth / mGlowHeight;
+ final int drawW = (int)(h*aspect);
+ final int drawH = h;
+ final int margin = (drawW-w)/2;
canvas.scale(mGlowScale, mGlowScale, w*0.5f, h*0.5f);
- mGlowBG.setBounds(0, 0, w, h);
+ mGlowBG.setBounds(-margin, 0, drawW-margin, drawH);
mGlowBG.setAlpha((int)(mDrawingAlpha * mGlowAlpha * 255));
mGlowBG.draw(canvas);
canvas.restore();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index a05fcc1..c65f581 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -282,7 +282,8 @@
public void refreshSignalCluster(SignalCluster cluster) {
cluster.setWifiIndicators(
- mWifiConnected, // only show wifi in the cluster if connected
+ // only show wifi in the cluster if connected or if wifi-only
+ mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
mWifiIconId,
mWifiActivityIconId,
mContentDescriptionWifi);
@@ -786,7 +787,7 @@
if (mDataAndWifiStacked) {
mWifiIconId = 0;
} else {
- mWifiIconId = mWifiEnabled ? WifiIcons.WIFI_SIGNAL_STRENGTH[0][0] : 0;
+ mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
}
mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index f41d99c..0284644 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -36,7 +36,6 @@
import android.widget.LinearLayout;
import com.android.systemui.ExpandHelper;
-import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.statusbar.NotificationData;
@@ -62,9 +61,6 @@
HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>();
private SwipeHelper mSwipeHelper;
- private ExpandHelper mExpandHelper;
-
- private Gefingerpoken mCurrentHelper;
// Flag set during notification removal animation to avoid causing too much work until
// animation is done
@@ -81,8 +77,6 @@
setOrientation(LinearLayout.VERTICAL);
- setMotionEventSplittingEnabled(false);
-
if (DEBUG) {
setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
@Override
@@ -101,9 +95,6 @@
float densityScale = getResources().getDisplayMetrics().density;
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
- int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
- int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
- mExpandHelper = new ExpandHelper(mContext, this, minHeight, maxHeight);
}
public void setLongPressListener(View.OnLongClickListener listener) {
@@ -135,39 +126,17 @@
if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
if (DEBUG) logLayoutTransition();
- MotionEvent cancellation = MotionEvent.obtain(ev);
- cancellation.setAction(MotionEvent.ACTION_CANCEL);
-
- if (mSwipeHelper.onInterceptTouchEvent(ev)) {
- if (DEBUG) Log.v(TAG, "will swipe");
- mCurrentHelper = mSwipeHelper;
- mExpandHelper.onInterceptTouchEvent(cancellation);
- return true;
- } else if (mExpandHelper.onInterceptTouchEvent(ev)) {
- if (DEBUG) Log.v(TAG, "will stretch");
- mCurrentHelper = mExpandHelper;
- mSwipeHelper.onInterceptTouchEvent(cancellation);
- return true;
- } else {
- mCurrentHelper = null;
- if (super.onInterceptTouchEvent(ev)) {
- if (DEBUG) Log.v(TAG, "intercepting ourselves");
- mSwipeHelper.onInterceptTouchEvent(cancellation);
- mExpandHelper.onInterceptTouchEvent(cancellation);
- return true;
- }
- }
- return false;
+ return mSwipeHelper.onInterceptTouchEvent(ev) ||
+ super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (DEBUG) Log.v(TAG, "onTouchEvent()");
if (DEBUG) logLayoutTransition();
- if (mCurrentHelper != null) {
- return mCurrentHelper.onTouchEvent(ev);
- }
- return super.onTouchEvent(ev);
+
+ return mSwipeHelper.onTouchEvent(ev) ||
+ super.onTouchEvent(ev);
}
public boolean canChildBeDismissed(View v) {
@@ -202,6 +171,13 @@
public View getChildAtPosition(MotionEvent ev) {
return getChildAtPosition(ev.getX(), ev.getY());
}
+
+ public View getChildAtRawPosition(float touchX, float touchY) {
+ int[] location = new int[2];
+ getLocationOnScreen(location);
+ return getChildAtPosition((float) (touchX - location[0]), (float) (touchY - location[1]));
+ }
+
public View getChildAtPosition(float touchX, float touchY) {
// find the view under the pointer, accounting for GONE views
final int count = getChildCount();
diff --git a/policy/src/com/android/internal/policy/impl/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
index c46b94a..737ea47 100644
--- a/policy/src/com/android/internal/policy/impl/FaceUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
@@ -300,7 +300,18 @@
* onServiceConnected() callback is received.
*/
void handleServiceConnected() {
- if (DEBUG) Log.d(TAG, "handleServiceConnected()");
+ Log.d(TAG, "handleServiceConnected()");
+
+ // It is possible that an unbind has occurred in the time between the bind and when this
+ // function is reached. If an unbind has already occurred, proceeding on to call startUi()
+ // can result in a fatal error. Note that the onServiceConnected() callback is
+ // asynchronous, so this possibility would still exist if we executed this directly in
+ // onServiceConnected() rather than using a handler.
+ if (!mBoundToService) {
+ Log.d(TAG, "Dropping startUi() in handleServiceConnected() because no longer bound");
+ return;
+ }
+
try {
mService.registerCallback(mFaceUnlockCallback);
} catch (RemoteException e) {
@@ -452,25 +463,12 @@
* Tells the Face Unlock service to start displaying its UI and start processing.
*/
private void startUi(IBinder windowToken, int x, int y, int w, int h) {
- Log.d(TAG, "startUi()");
+ if (DEBUG) Log.d(TAG, "startUi()");
synchronized (mServiceRunningLock) {
if (!mServiceRunning) {
- if (DEBUG) Log.d(TAG, "Starting Face Unlock");
+ Log.d(TAG, "Starting Face Unlock");
try {
- // TODO: these checks and logs are for tracking down bug 6409767 and can be
- // removed when that bug is fixed.
- if (mService == null) {
- Log.d(TAG, "mService is null");
- }
- if (windowToken == null) {
- Log.d(TAG, "windowToken is null");
- }
- if (mLockPatternUtils == null) {
- Log.d(TAG, "mLockPatternUtils is null");
- }
- Log.d(TAG, "x,y,w,h,live: " + x + "," + y + "," + w + "," + h + ", no");
mService.startUi(windowToken, x, y, w, h, false);
- Log.d(TAG, "mService.startUi() called");
} catch (RemoteException e) {
Log.e(TAG, "Caught exception starting Face Unlock: " + e.toString());
return;
@@ -492,7 +490,7 @@
// screen is turned off. That's why we check.
synchronized (mServiceRunningLock) {
if (mServiceRunning) {
- if (DEBUG) Log.d(TAG, "Stopping Face Unlock");
+ Log.d(TAG, "Stopping Face Unlock");
try {
mService.stopUi();
} catch (RemoteException e) {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index 7f432bf..504bb63 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -117,7 +117,6 @@
final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
| WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
- | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
| WindowManager.LayoutParams.FLAG_SLIPPERY
/*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ;
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 8ea334e..22f70a5 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -32,6 +32,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Vibrator;
@@ -45,7 +46,6 @@
import android.media.AudioManager;
import android.os.RemoteException;
import android.provider.MediaStore;
-import android.provider.Settings;
import java.io.File;
@@ -252,13 +252,19 @@
}
}
+ // This code should be the same as that in SearchPanelView
+ public boolean isAssistantAvailable() {
+ Intent intent = getAssistIntent();
+ return intent == null ? false
+ : mContext.getPackageManager().queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
+ }
+
private Intent getAssistIntent() {
Intent intent = null;
- if (mSearchManager == null) {
- mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
- }
- if (mSearchManager != null) {
- ComponentName globalSearchActivity = mSearchManager.getGlobalSearchActivity();
+ SearchManager searchManager = getSearchManager();
+ if (searchManager != null) {
+ ComponentName globalSearchActivity = searchManager.getGlobalSearchActivity();
if (globalSearchActivity != null) {
intent = new Intent(Intent.ACTION_ASSIST);
intent.setPackage(globalSearchActivity.getPackageName());
@@ -271,6 +277,13 @@
return intent;
}
+ private SearchManager getSearchManager() {
+ if (mSearchManager == null) {
+ mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+ }
+ return mSearchManager;
+ }
+
class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener,
UnlockWidgetCommonMethods {
private final MultiWaveView mMultiWaveView;
@@ -517,14 +530,12 @@
.isTargetPresent(com.android.internal.R.drawable.ic_lockscreen_search)
: false;
- // TODO: test to see if search is available
- boolean searchActionAvailable = true;
-
if (disabledByAdmin) {
Log.v(TAG, "Camera disabled by Device Policy");
} else if (disabledBySimState) {
Log.v(TAG, "Camera disabled by Sim State");
}
+ boolean searchActionAvailable = isAssistantAvailable();
mCameraDisabled = disabledByAdmin || disabledBySimState || !cameraTargetPresent;
mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent;
mUnlockWidgetMethods.updateResources();
diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
index 17e671d..9a6d2cc 100644
--- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -41,7 +41,7 @@
class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient
implements KeyguardScreen {
- private static final boolean DEBUG = true; /* TODO: revert before JB release */
+ private static final boolean DEBUG = false;
private static final String TAG = "UnlockScreen";
// how long before we clear the wrong pattern
@@ -321,7 +321,6 @@
implements LockPatternView.OnPatternListener {
public void onPatternStart() {
- if (DEBUG) Log.d(TAG, "Got pattern start");
mLockPatternView.removeCallbacks(mCancelPatternRunnable);
}
@@ -337,7 +336,6 @@
// Give just a little extra time if they hit one of the first few dots
mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS);
}
- if (DEBUG) Log.d(TAG, "Got pattern cell");
}
public void onPatternDetected(List<LockPatternView.Cell> pattern) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 3147ba7..cee01ac 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -158,7 +158,7 @@
static final boolean DEBUG = false;
static final boolean localLOGV = false;
static final boolean DEBUG_LAYOUT = false;
- static final boolean DEBUG_FALLBACK = false;
+ static final boolean DEBUG_INPUT = false;
static final boolean SHOW_STARTING_ANIMATIONS = true;
static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
@@ -179,7 +179,6 @@
static final int LONG_PRESS_HOME_NOTHING = 0;
static final int LONG_PRESS_HOME_RECENT_DIALOG = 1;
static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 2;
- static final int LONG_PRESS_HOME_VOICE_SEARCH = 3;
// wallpaper is at the bottom, though the window manager may move it.
static final int WALLPAPER_LAYER = 2;
@@ -322,7 +321,8 @@
static final int RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS = 0;
static final int RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW = 1;
- static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 2;
+ static final int RECENT_APPS_BEHAVIOR_DISMISS = 2;
+ static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 3;
RecentApplicationsDialog mRecentAppsDialog;
int mRecentAppsDialogHeldModifiers;
@@ -410,6 +410,10 @@
int mSystemLeft, mSystemTop, mSystemRight, mSystemBottom;
// For applications requesting stable content insets, these are them.
int mStableLeft, mStableTop, mStableRight, mStableBottom;
+ // For applications requesting stable content insets but have also set the
+ // fullscreen window flag, these are the stable dimensions without the status bar.
+ int mStableFullscreenLeft, mStableFullscreenTop;
+ int mStableFullscreenRight, mStableFullscreenBottom;
// During layout, the current screen borders with all outer decoration
// (status bar, input method dock) accounted for.
int mCurLeft, mCurTop, mCurRight, mCurBottom;
@@ -500,6 +504,7 @@
ShortcutManager mShortcutManager;
PowerManager.WakeLock mBroadcastWakeLock;
+ boolean mHavePendingMediaKeyRepeatWithWakeLock;
// Fallback actions by key code.
private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions =
@@ -507,6 +512,8 @@
private static final int MSG_ENABLE_POINTER_LOCATION = 1;
private static final int MSG_DISABLE_POINTER_LOCATION = 2;
+ private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
+ private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
private class PolicyHandler extends Handler {
@Override
@@ -518,6 +525,12 @@
case MSG_DISABLE_POINTER_LOCATION:
disablePointerLocation();
break;
+ case MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK:
+ dispatchMediaKeyWithWakeLock((KeyEvent)msg.obj);
+ break;
+ case MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK:
+ dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj);
+ break;
}
}
}
@@ -758,9 +771,6 @@
mLongPressOnHomeBehavior > LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
}
- if (hasNavigationBar()) {
- mLongPressOnHomeBehavior = LONG_PRESS_HOME_VOICE_SEARCH;
- }
}
if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
@@ -780,18 +790,6 @@
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException when showing recent apps", e);
}
- } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_VOICE_SEARCH) {
- Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
- try {
- intent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "Unable to launch. tag=" + TAG + " intent=" + intent, e);
- } catch (SecurityException e) {
- Log.e(TAG, "PhoneWindowManager does not have the permission to launch " +
- "tag=" + TAG + " intent=" + intent, e);
- }
}
}
@@ -809,6 +807,7 @@
if (mRecentAppsDialog.isShowing()) {
switch (behavior) {
case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS:
+ case RECENT_APPS_BEHAVIOR_DISMISS:
mRecentAppsDialog.dismiss();
break;
case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
@@ -830,6 +829,7 @@
}
mRecentAppsDialog.show();
break;
+ case RECENT_APPS_BEHAVIOR_DISMISS:
case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
default:
break;
@@ -1701,7 +1701,7 @@
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
- if (false) {
+ if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
+ repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed
+ " canceled=" + canceled);
@@ -1849,7 +1849,7 @@
}
return 0;
} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
- if (down && repeatCount == 0) {
+ if (down && repeatCount == 0 && !keyguardOn) {
showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS);
}
return -1;
@@ -1886,27 +1886,29 @@
}
// Invoke shortcuts using Meta.
- if (down && repeatCount == 0
+ if (down && repeatCount == 0 && !keyguardOn
&& (metaState & KeyEvent.META_META_ON) != 0) {
final KeyCharacterMap kcm = event.getKeyCharacterMap();
- Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
- metaState & ~(KeyEvent.META_META_ON
- | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
- if (shortcutIntent != null) {
- shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- mContext.startActivity(shortcutIntent);
- } catch (ActivityNotFoundException ex) {
- Slog.w(TAG, "Dropping shortcut key combination because "
- + "the activity to which it is registered was not found: "
- + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+ if (kcm.isPrintingKey(keyCode)) {
+ Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
+ metaState & ~(KeyEvent.META_META_ON
+ | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
+ if (shortcutIntent != null) {
+ shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ mContext.startActivity(shortcutIntent);
+ } catch (ActivityNotFoundException ex) {
+ Slog.w(TAG, "Dropping shortcut key combination because "
+ + "the activity to which it is registered was not found: "
+ + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+ }
+ return -1;
}
- return -1;
}
}
// Handle application launch keys.
- if (down && repeatCount == 0) {
+ if (down && repeatCount == 0 && !keyguardOn) {
String category = sApplicationLaunchKeyCategories.get(keyCode);
if (category != null) {
Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
@@ -1924,7 +1926,7 @@
// Display task switcher for ALT-TAB or Meta-TAB.
if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
- if (mRecentAppsDialogHeldModifiers == 0) {
+ if (mRecentAppsDialogHeldModifiers == 0 && !keyguardOn) {
final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
|| KeyEvent.metaStateHasModifiers(
@@ -1937,7 +1939,8 @@
} else if (!down && mRecentAppsDialogHeldModifiers != 0
&& (metaState & mRecentAppsDialogHeldModifiers) == 0) {
mRecentAppsDialogHeldModifiers = 0;
- showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH);
+ showOrHideRecentAppsDialog(keyguardOn ? RECENT_APPS_BEHAVIOR_DISMISS :
+ RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH);
}
// Let the application handle the key.
@@ -1948,7 +1951,7 @@
@Override
public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
// Note: This method is only called if the initial down was unhandled.
- if (DEBUG_FALLBACK) {
+ if (DEBUG_INPUT) {
Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction()
+ ", flags=" + event.getFlags()
+ ", keyCode=" + event.getKeyCode()
@@ -1975,7 +1978,7 @@
}
if (fallbackAction != null) {
- if (DEBUG_FALLBACK) {
+ if (DEBUG_INPUT) {
Slog.d(TAG, "Fallback: keyCode=" + fallbackAction.keyCode
+ " metaState=" + Integer.toHexString(fallbackAction.metaState));
}
@@ -2002,7 +2005,7 @@
}
}
- if (DEBUG_FALLBACK) {
+ if (DEBUG_INPUT) {
if (fallbackEvent == null) {
Slog.d(TAG, "No fallback.");
} else {
@@ -2153,22 +2156,31 @@
public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
final int fl = attrs.flags;
+ final int systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
- if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
+ if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
int availRight, availBottom;
if (mCanHideNavigationBar &&
- (attrs.systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
+ (systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
availRight = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
availBottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
} else {
availRight = mRestrictedScreenLeft + mRestrictedScreenWidth;
availBottom = mRestrictedScreenTop + mRestrictedScreenHeight;
}
- if ((attrs.systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
- contentInset.set(mStableLeft, mStableTop,
- availRight - mStableRight, availBottom - mStableBottom);
- } else if ((attrs.systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
+ if ((systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+ if ((fl & FLAG_FULLSCREEN) != 0) {
+ contentInset.set(mStableFullscreenLeft, mStableFullscreenTop,
+ availRight - mStableFullscreenRight,
+ availBottom - mStableFullscreenBottom);
+ } else {
+ contentInset.set(mStableLeft, mStableTop,
+ availRight - mStableRight, availBottom - mStableBottom);
+ }
+ } else if ((fl & FLAG_FULLSCREEN) != 0) {
+ contentInset.setEmpty();
+ } else if ((systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) {
contentInset.set(mCurLeft, mCurTop,
availRight - mCurRight, availBottom - mCurBottom);
@@ -2189,10 +2201,14 @@
mRestrictedScreenLeft = mRestrictedScreenTop = 0;
mRestrictedScreenWidth = displayWidth;
mRestrictedScreenHeight = displayHeight;
- mDockLeft = mContentLeft = mStableLeft = mSystemLeft = mCurLeft = 0;
- mDockTop = mContentTop = mStableTop = mSystemTop = mCurTop = 0;
- mDockRight = mContentRight = mStableRight = mSystemRight = mCurRight = displayWidth;
- mDockBottom = mContentBottom = mStableBottom = mSystemBottom = mCurBottom = displayHeight;
+ mDockLeft = mContentLeft = mStableLeft = mStableFullscreenLeft
+ = mSystemLeft = mCurLeft = 0;
+ mDockTop = mContentTop = mStableTop = mStableFullscreenTop
+ = mSystemTop = mCurTop = 0;
+ mDockRight = mContentRight = mStableRight = mStableFullscreenRight
+ = mSystemRight = mCurRight = displayWidth;
+ mDockBottom = mContentBottom = mStableBottom = mStableFullscreenBottom
+ = mSystemBottom = mCurBottom = displayHeight;
mDockLayer = 0x10000000;
mStatusBarLayer = -1;
@@ -2245,7 +2261,7 @@
}
}
mTmpNavigationFrame.set(0, top, displayWidth, displayHeight);
- mStableBottom = mTmpNavigationFrame.top;
+ mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
if (navVisible) {
mNavigationBar.showLw(true);
mDockBottom = mTmpNavigationFrame.top;
@@ -2269,7 +2285,7 @@
}
}
mTmpNavigationFrame.set(left, 0, displayWidth, displayHeight);
- mStableRight = mTmpNavigationFrame.left;
+ mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
if (navVisible) {
mNavigationBar.showLw(true);
mDockRight = mTmpNavigationFrame.left;
@@ -2407,7 +2423,25 @@
pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
? attached.getFrameLw() : df);
}
-
+
+ private void applyStableConstraints(int sysui, int fl, Rect r) {
+ if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+ // If app is requesting a stable layout, don't let the
+ // content insets go below the stable values.
+ if ((fl & FLAG_FULLSCREEN) != 0) {
+ if (r.left < mStableFullscreenLeft) r.left = mStableFullscreenLeft;
+ if (r.top < mStableFullscreenTop) r.top = mStableFullscreenTop;
+ if (r.right > mStableFullscreenRight) r.right = mStableFullscreenRight;
+ if (r.bottom > mStableFullscreenBottom) r.bottom = mStableFullscreenBottom;
+ } else {
+ if (r.left < mStableLeft) r.left = mStableLeft;
+ if (r.top < mStableTop) r.top = mStableTop;
+ if (r.right > mStableRight) r.right = mStableRight;
+ if (r.bottom > mStableBottom) r.bottom = mStableBottom;
+ }
+ }
+ }
+
/** {@inheritDoc} */
public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
WindowState attached) {
@@ -2514,14 +2548,7 @@
cf.right = mContentRight;
cf.bottom = mContentBottom;
}
- if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
- // If app is requesting a stable layout, don't let the
- // content insets go below the stable values.
- if (cf.left < mStableLeft) cf.left = mStableLeft;
- if (cf.top < mStableTop) cf.top = mStableTop;
- if (cf.right > mStableRight) cf.right = mStableRight;
- if (cf.bottom > mStableBottom) cf.bottom = mStableBottom;
- }
+ applyStableConstraints(sysUiFl, fl, cf);
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
vf.left = mCurLeft;
vf.top = mCurTop;
@@ -2603,14 +2630,7 @@
pf.bottom = df.bottom = cf.bottom
= mRestrictedScreenTop+mRestrictedScreenHeight;
}
- if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
- // If app is requesting a stable layout, don't let the
- // content insets go below the stable values.
- if (cf.left < mStableLeft) cf.left = mStableLeft;
- if (cf.top < mStableTop) cf.top = mStableTop;
- if (cf.right > mStableRight) cf.right = mStableRight;
- if (cf.bottom > mStableBottom) cf.bottom = mStableBottom;
- }
+ applyStableConstraints(sysUiFl, fl, cf);
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
vf.left = mCurLeft;
vf.top = mCurTop;
@@ -3078,7 +3098,7 @@
return 0;
}
- if (false) {
+ if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
}
@@ -3300,8 +3320,13 @@
// Only do this if we would otherwise not pass it to the user. In that
// case, the PhoneWindow class will do the same thing, except it will
// only do it if the showing app doesn't process the key on its own.
+ // Note that we need to make a copy of the key event here because the
+ // original key event will be recycled when we return.
mBroadcastWakeLock.acquire();
- mHandler.post(new PassHeadsetKey(new KeyEvent(event)));
+ Message msg = mHandler.obtainMessage(MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK,
+ new KeyEvent(event));
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
}
break;
}
@@ -3350,24 +3375,58 @@
return result;
}
- class PassHeadsetKey implements Runnable {
- KeyEvent mKeyEvent;
-
- PassHeadsetKey(KeyEvent keyEvent) {
- mKeyEvent = keyEvent;
+ void dispatchMediaKeyWithWakeLock(KeyEvent event) {
+ if (DEBUG_INPUT) {
+ Slog.d(TAG, "dispatchMediaKeyWithWakeLock: " + event);
}
- public void run() {
- if (ActivityManagerNative.isSystemReady()) {
- IAudioService audioService = getAudioService();
- if (audioService != null) {
- try {
- audioService.dispatchMediaKeyEventUnderWakelock(mKeyEvent);
- } catch (RemoteException e) {
- Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
- }
+ if (mHavePendingMediaKeyRepeatWithWakeLock) {
+ if (DEBUG_INPUT) {
+ Slog.d(TAG, "dispatchMediaKeyWithWakeLock: canceled repeat");
+ }
+
+ mHandler.removeMessages(MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK);
+ mHavePendingMediaKeyRepeatWithWakeLock = false;
+ mBroadcastWakeLock.release(); // pending repeat was holding onto the wake lock
+ }
+
+ dispatchMediaKeyWithWakeLockToAudioService(event);
+
+ if (event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getRepeatCount() == 0) {
+ mHavePendingMediaKeyRepeatWithWakeLock = true;
+
+ Message msg = mHandler.obtainMessage(
+ MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK, event);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg, ViewConfiguration.getKeyRepeatTimeout());
+ } else {
+ mBroadcastWakeLock.release();
+ }
+ }
+
+ void dispatchMediaKeyRepeatWithWakeLock(KeyEvent event) {
+ mHavePendingMediaKeyRepeatWithWakeLock = false;
+
+ KeyEvent repeatEvent = KeyEvent.changeTimeRepeat(event,
+ SystemClock.uptimeMillis(), 1, event.getFlags() | KeyEvent.FLAG_LONG_PRESS);
+ if (DEBUG_INPUT) {
+ Slog.d(TAG, "dispatchMediaKeyRepeatWithWakeLock: " + repeatEvent);
+ }
+
+ dispatchMediaKeyWithWakeLockToAudioService(repeatEvent);
+ mBroadcastWakeLock.release();
+ }
+
+ void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
+ if (ActivityManagerNative.isSystemReady()) {
+ IAudioService audioService = getAudioService();
+ if (audioService != null) {
+ try {
+ audioService.dispatchMediaKeyEventUnderWakelock(event);
+ } catch (RemoteException e) {
+ Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
}
- mBroadcastWakeLock.release();
}
}
}
@@ -4258,6 +4317,10 @@
pw.print(","); pw.print(mRestrictedScreenTop);
pw.print(") "); pw.print(mRestrictedScreenWidth);
pw.print("x"); pw.println(mRestrictedScreenHeight);
+ pw.print(prefix); pw.print("mStableFullscreen=("); pw.print(mStableFullscreenLeft);
+ pw.print(","); pw.print(mStableFullscreenTop);
+ pw.print(")-("); pw.print(mStableFullscreenRight);
+ pw.print(","); pw.print(mStableFullscreenBottom); pw.println(")");
pw.print(prefix); pw.print("mStable=("); pw.print(mStableLeft);
pw.print(","); pw.print(mStableTop);
pw.print(")-("); pw.print(mStableRight);
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 50bfee6..f80ac18 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "EventHub"
-#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include "EventHub.h"
@@ -767,7 +767,11 @@
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
const struct input_event& iev = readBuffer[i];
- nsecs_t delta = 0;
+ ALOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
+ device->path.string(),
+ (int) iev.time.tv_sec, (int) iev.time.tv_usec,
+ iev.type, iev.code, iev.value);
+
#ifdef HAVE_POSIX_CLOCKS
// Use the time specified in the event instead of the current time
// so that downstream code can get more accurate estimates of
@@ -782,23 +786,10 @@
// system call that also queries ktime_get_ts().
event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
+ nsecs_t(iev.time.tv_usec) * 1000LL;
- delta = now - event->when;
-
- // Only log verbose if events are older that 1ms
- if (delta > 1 * 1000000LL) {
- ALOGV("event time %lld, now %lld, delta %lldus", event->when, now, delta / 1000LL);
- }
+ ALOGV("event time %lld, now %lld", event->when, now);
#else
event->when = now;
#endif
- if (delta > 1 * 1000000LL) {
- ALOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
- device->path.string(),
- (int) iev.time.tv_sec, (int) iev.time.tv_usec,
- iev.type, iev.code, iev.value);
- }
-
-
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 23f2fdd..df2e1aa 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -49,6 +49,7 @@
import android.util.Slog;
import android.util.TypedValue;
import android.util.Xml;
+import android.view.WindowManager;
import android.widget.RemoteViews;
import com.android.internal.appwidget.IAppWidgetHost;
@@ -171,6 +172,7 @@
boolean mSafeMode;
int mUserId;
boolean mStateLoaded;
+ int mMaxWidgetBitmapMemory;
// These are for debugging only -- widgets are going missing in some rare instances
ArrayList<Provider> mDeletedProviders = new ArrayList<Provider>();
@@ -181,6 +183,14 @@
mPm = AppGlobals.getPackageManager();
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mUserId = userId;
+ computeMaximumWidgetBitmapMemory();
+ }
+
+ void computeMaximumWidgetBitmapMemory() {
+ WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ int height = wm.getDefaultDisplay().getRawHeight();
+ int width = wm.getDefaultDisplay().getRawWidth();
+ mMaxWidgetBitmapMemory = 4 * width * height;
}
public void systemReady(boolean safeMode) {
@@ -806,6 +816,15 @@
if (appWidgetIds == null) {
return;
}
+
+ int bitmapMemoryUsage = views.estimateMemoryUsage();
+ if (bitmapMemoryUsage > mMaxWidgetBitmapMemory) {
+ throw new IllegalArgumentException("RemoteViews for widget update exceeds maximum" +
+ " bitmap memory usage (used: " + bitmapMemoryUsage + ", max: " +
+ mMaxWidgetBitmapMemory + ") The total memory cannot exceed that required to" +
+ " fill the device's screen once.");
+ }
+
if (appWidgetIds.length == 0) {
return;
}
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 6a6c585..a15d3bb 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -148,6 +148,7 @@
mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
event.getCode(), event.getRawEvent()));
} else {
+ log("POST<- {" + rawEvent + "}");
mResponseQueue.add(event.getCmdNumber(), event);
}
} catch (IllegalArgumentException e) {
@@ -327,6 +328,7 @@
loge("timed-out waiting for response to " + logCmd);
throw new NativeDaemonFailureException(logCmd, event);
}
+ log("RMV <- {" + event + "}");
events.add(event);
} while (event.isClassContinue());
@@ -337,6 +339,7 @@
throw new NativeDaemonFailureException(logCmd, event);
}
+ log("RTN <- {" + logCmd + "}");
return events.toArray(new NativeDaemonEvent[events.size()]);
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 4536a6d..e2852b5 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -166,7 +166,7 @@
}
mConnector = new NativeDaemonConnector(
- new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 50);
+ new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 80);
mThread = new Thread(mConnector, NETD_TAG);
// Add ourself to the Watchdog monitors.
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 8429086..78c0c12 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -489,7 +489,8 @@
synchronized (mNotifications) {
final StatusBarNotification n = mNotifications.remove(key);
if (n == null) {
- throw new IllegalArgumentException("removeNotification key not found: " + key);
+ Slog.e(TAG, "removeNotification key not found: " + key);
+ return;
}
if (mBar != null) {
try {
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index dd037df..1f03d17 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -578,6 +578,8 @@
*/
public synchronized boolean setWifiEnabled(boolean enable) {
enforceChangePermission();
+ Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
if (DBG) {
Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 1937bad..f23b25e 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -35,6 +35,7 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.hardware.input.InputManager;
@@ -532,6 +533,18 @@
for (int i = 0, count = installedServices.size(); i < count; i++) {
ResolveInfo resolveInfo = installedServices.get(i);
+ ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ // For now we are enforcing this if the target version is JellyBean or
+ // higher and in a later release we will enforce this for everyone.
+ if (serviceInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN
+ && !android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
+ serviceInfo.permission)) {
+ Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName(
+ serviceInfo.packageName, serviceInfo.name).flattenToShortString()
+ + ": it does not require the permission "
+ + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
+ continue;
+ }
AccessibilityServiceInfo accessibilityServiceInfo;
try {
accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 497ee4b..3936c18 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1064,7 +1064,7 @@
mInstaller.moveFiles();
// Prune any system packages that no longer exist.
- final List<String> possiblyDeletedSystemApps = new ArrayList<String>();
+ final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
if (!mOnlyCore) {
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
@@ -1104,7 +1104,10 @@
mInstaller.remove(ps.name, 0);
sUserManager.removePackageForAllUsers(ps.name);
} else {
- possiblyDeletedSystemApps.add(ps.name);
+ final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
+ if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
+ possiblyDeletedUpdatedSystemApps.add(ps.name);
+ }
}
}
}
@@ -1135,18 +1138,33 @@
scanMode, 0);
/**
- * Remove disable package settings for any system apps
- * that were removed via an OTA.
+ * Remove disable package settings for any updated system
+ * apps that were removed via an OTA. If they're not a
+ * previously-updated app, remove them completely.
+ * Otherwise, just revoke their system-level permissions.
*/
- for (String deletedAppName : possiblyDeletedSystemApps) {
+ for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
- if (deletedPkg != null) {
- mSettings.removeDisabledSystemPackageLPw(deletedAppName);
+ mSettings.removeDisabledSystemPackageLPw(deletedAppName);
+
+ String msg;
+ if (deletedPkg == null) {
+ msg = "Updated system package " + deletedAppName
+ + " no longer exists; wiping its data";
+
+ mInstaller.remove(deletedAppName, 0);
+ sUserManager.removePackageForAllUsers(deletedAppName);
+ } else {
+ msg = "Updated system app + " + deletedAppName
+ + " no longer present; removing system privileges for "
+ + deletedAppName;
+
deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
}
+ reportSettingsProblem(Log.WARN, msg);
}
} else {
mAppInstallObserver = null;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b3ac6f1..f460f9b 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -1173,8 +1173,7 @@
if (DEBUG_INPUT_METHOD) {
Slog.i(TAG, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding());
if (!w.isVisibleOrAdding()) {
- Slog.i(TAG, " mSurface=" + w.mWinAnimator.mSurface + " reportDestroy="
- + w.mWinAnimator.mReportDestroySurface
+ Slog.i(TAG, " mSurface=" + w.mWinAnimator.mSurface
+ " relayoutCalled=" + w.mRelayoutCalled + " viewVis=" + w.mViewVisibility
+ " policyVis=" + w.mPolicyVisibility + " attachHid=" + w.mAttachedHidden
+ " exiting=" + w.mExiting + " destroying=" + w.mDestroying);
@@ -2651,7 +2650,7 @@
int requestedHeight, int viewVisibility, int flags,
Rect outFrame, Rect outContentInsets,
Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
- boolean displayed = false;
+ boolean toBeDisplayed = false;
boolean inTouchMode;
boolean configChanged;
boolean surfaceChanged = false;
@@ -2754,7 +2753,7 @@
}
if (viewVisibility == View.VISIBLE &&
(win.mAppToken == null || !win.mAppToken.clientHidden)) {
- displayed = !win.isVisibleLw();
+ toBeDisplayed = !win.isVisibleLw();
if (win.mExiting) {
winAnimator.cancelExitAnimationForNextAnimationLocked();
win.mExiting = false;
@@ -2766,7 +2765,7 @@
if (oldVisibility == View.GONE) {
winAnimator.mEnterAnimationPending = true;
}
- if (displayed) {
+ if (toBeDisplayed) {
if (win.isDrawnLw() && okToDisplay()) {
winAnimator.applyEnterAnimationLocked();
}
@@ -2792,7 +2791,7 @@
if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
// To change the format, we need to re-build the surface.
winAnimator.destroySurfaceLocked();
- displayed = true;
+ toBeDisplayed = true;
surfaceChanged = true;
}
try {
@@ -2802,8 +2801,6 @@
Surface surface = winAnimator.createSurfaceLocked();
if (surface != null) {
outSurface.copyFrom(surface);
- winAnimator.mReportDestroySurface = false;
- winAnimator.mSurfacePendingDestroy = false;
if (SHOW_TRANSACTIONS) Slog.i(TAG,
" OUT SURFACE " + outSurface + ": copied");
} else {
@@ -2820,7 +2817,7 @@
Binder.restoreCallingIdentity(origId);
return 0;
}
- if (displayed) {
+ if (toBeDisplayed) {
focusMayChange = true;
}
if (win.mAttrs.type == TYPE_INPUT_METHOD
@@ -2845,11 +2842,10 @@
winAnimator.mEnterAnimationPending = false;
if (winAnimator.mSurface != null) {
if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
- + ": mExiting=" + win.mExiting
- + " mSurfacePendingDestroy=" + winAnimator.mSurfacePendingDestroy);
+ + ": mExiting=" + win.mExiting);
// If we are not currently running the exit animation, we
// need to see about starting one.
- if (!win.mExiting || winAnimator.mSurfacePendingDestroy) {
+ if (!win.mExiting) {
surfaceChanged = true;
// Try starting an animation; if there isn't one, we
// can destroy the surface right away.
@@ -2857,7 +2853,7 @@
if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
- if (!winAnimator.mSurfacePendingDestroy && win.isWinVisibleLw() &&
+ if (win.isWinVisibleLw() &&
winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = true;
win.mExiting = true;
@@ -2880,22 +2876,8 @@
}
}
- if (winAnimator.mSurface == null || (win.getAttrs().flags
- & WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING) == 0
- || winAnimator.mSurfacePendingDestroy) {
- // We could be called from a local process, which
- // means outSurface holds its current surface. Ensure the
- // surface object is cleared, but we don't necessarily want
- // it actually destroyed at this point.
- winAnimator.mSurfacePendingDestroy = false;
- outSurface.release();
- if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
- } else if (winAnimator.mSurface != null) {
- if (DEBUG_VISIBILITY) Slog.i(TAG,
- "Keeping surface, will report destroy: " + win);
- winAnimator.mReportDestroySurface = true;
- outSurface.copyFrom(winAnimator.mSurface);
- }
+ outSurface.release();
+ if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
}
if (focusMayChange) {
@@ -2912,7 +2894,7 @@
boolean assignLayers = false;
if (imMayMove) {
- if (moveInputMethodWindowsIfNeededLocked(false) || displayed) {
+ if (moveInputMethodWindowsIfNeededLocked(false) || toBeDisplayed) {
// Little hack here -- we -should- be able to rely on the
// function to return true if the IME has moved and needs
// its layer recomputed. However, if the IME was hidden
@@ -2934,7 +2916,7 @@
}
configChanged = updateOrientationFromAppTokensLocked(false);
performLayoutAndPlaceSurfacesLocked();
- if (displayed && win.mIsWallpaper) {
+ if (toBeDisplayed && win.mIsWallpaper) {
updateWallpaperOffsetLocked(win, mAppDisplayWidth, mAppDisplayHeight, false);
}
if (win.mAppToken != null) {
@@ -2970,7 +2952,7 @@
Binder.restoreCallingIdentity(origId);
return (inTouchMode ? WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE : 0)
- | (displayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0)
+ | (toBeDisplayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0)
| (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0)
| (animating ? WindowManagerImpl.RELAYOUT_RES_ANIMATING : 0);
}
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 1fd80c2..e2a904f 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -679,8 +679,7 @@
*/
boolean isVisibleOrAdding() {
final AppWindowToken atoken = mAppToken;
- return ((mHasSurface && !mWinAnimator.mReportDestroySurface)
- || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
+ return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
&& mPolicyVisibility && !mAttachedHidden
&& (atoken == null || !atoken.hiddenRequested)
&& !mExiting && !mDestroying;
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 5516dea..355db6e 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -71,8 +71,6 @@
Surface mSurface;
Surface mPendingDestroySurface;
- boolean mReportDestroySurface;
- boolean mSurfacePendingDestroy;
/**
* Set when we have changed the size of the surface, to know that
@@ -561,8 +559,6 @@
Surface createSurfaceLocked() {
if (mSurface == null) {
- mReportDestroySurface = false;
- mSurfacePendingDestroy = false;
if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
"createSurface " + this + ": mDrawState=DRAW_PENDING");
mDrawState = DRAW_PENDING;
@@ -694,7 +690,6 @@
mWin.mAppToken.startingDisplayed = false;
}
- mDrawState = NO_SURFACE;
if (mSurface != null) {
int i = mWin.mChildWindows.size();
@@ -704,17 +699,6 @@
c.mAttachedHidden = true;
}
- if (mReportDestroySurface) {
- mReportDestroySurface = false;
- mSurfacePendingDestroy = true;
- try {
- mWin.mClient.dispatchGetNewSurface();
- // We'll really destroy on the next time around.
- return;
- } catch (RemoteException e) {
- }
- }
-
try {
if (DEBUG_VISIBILITY) {
RuntimeException e = null;
@@ -760,6 +744,7 @@
mSurfaceShown = false;
mSurface = null;
mWin.mHasSurface =false;
+ mDrawState = NO_SURFACE;
}
}
@@ -1147,7 +1132,7 @@
}
} else {
if (DEBUG_ANIM) {
- Slog.v(TAG, "prepareSurface: No changes in animation for " + mWin);
+ // Slog.v(TAG, "prepareSurface: No changes in animation for " + mWin);
}
displayed = true;
}
diff --git a/services/jni/com_android_server_PowerManagerService.cpp b/services/jni/com_android_server_PowerManagerService.cpp
index a47f8fd..0904bdd 100644
--- a/services/jni/com_android_server_PowerManagerService.cpp
+++ b/services/jni/com_android_server_PowerManagerService.cpp
@@ -83,11 +83,9 @@
}
void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
- if (gPowerModule) {
- // Tell the power HAL when user activity occurs.
- if (gPowerModule->powerHint) {
- gPowerModule->powerHint(gPowerModule, POWER_HINT_INTERACTION, NULL);
- }
+ // Tell the power HAL when user activity occurs.
+ if (gPowerModule && gPowerModule->powerHint) {
+ gPowerModule->powerHint(gPowerModule, POWER_HINT_INTERACTION, NULL);
}
if (gPowerManagerServiceObj) {
@@ -131,16 +129,11 @@
status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,
(hw_module_t const**)&gPowerModule);
- if (err) {
- String8 msg;
- msg.appendFormat("Couldn't load %s module (%s)",
- POWER_HARDWARE_MODULE_ID, strerror(-err));
- ALOGE("%s", msg.string());
- jniThrowRuntimeException(env, msg.string());
- return;
+ if (!err) {
+ gPowerModule->init(gPowerModule);
+ } else {
+ ALOGE("Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err));
}
-
- gPowerModule->init(gPowerModule);
}
static void nativeSetPowerState(JNIEnv* env,
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index cc3c328..3f66de6 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -37,13 +37,15 @@
<application>
<uses-library android:name="android.test.runner" />
- <service android:name="com.android.server.AccessibilityManagerServiceTest$MyFirstMockAccessibilityService">
+ <service android:name="com.android.server.AccessibilityManagerServiceTest$MyFirstMockAccessibilityService"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
</service>
- <service android:name="com.android.server.AccessibilityManagerServiceTest$MySecondMockAccessibilityService">
+ <service android:name="com.android.server.AccessibilityManagerServiceTest$MySecondMockAccessibilityService"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 7c70a7e..0033ceb 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -1256,6 +1256,7 @@
pw.println(" mRetryOverride=" + mRetryOverride);
pw.println(" mRefCount=" + mRefCount);
pw.println(" userData=" + userData);
+ if (mRetryMgr != null) pw.println(" " + mRetryMgr);
pw.flush();
}
}
diff --git a/telephony/java/com/android/internal/telephony/RetryManager.java b/telephony/java/com/android/internal/telephony/RetryManager.java
index 29bd104..ae451b9 100644
--- a/telephony/java/com/android/internal/telephony/RetryManager.java
+++ b/telephony/java/com/android/internal/telephony/RetryManager.java
@@ -74,7 +74,8 @@
*/
public class RetryManager {
static public final String LOG_TAG = "RetryManager";
- static public final boolean DBG = false;
+ static public final boolean DBG = true;
+ static public final boolean VDBG = false;
/**
* Retry record with times in milli-seconds
@@ -107,9 +108,20 @@
/** Random number generator */
private Random rng = new Random();
+ private String mConfig;
+
/** Constructor */
public RetryManager() {
- if (DBG) log("constructor");
+ if (VDBG) log("constructor");
+ }
+
+ public String toString() {
+ String ret = "RetryManager: forever=" + mRetryForever + ", maxRetry=" + mMaxRetryCount +
+ ", retry=" + mRetryCount + ",\n " + mConfig;
+ for (RetryRec r : mRetryArray) {
+ ret += "\n " + r.mDelayTime + ":" + r.mRandomizationTime;
+ }
+ return ret;
}
/**
@@ -127,7 +139,7 @@
public boolean configure(int maxRetryCount, int retryTime, int randomizationTime) {
Pair<Boolean, Integer> value;
- if (DBG) log("configure: " + maxRetryCount + ", " + retryTime + "," + randomizationTime);
+ if (VDBG) log("configure: " + maxRetryCount + ", " + retryTime + "," + randomizationTime);
if (!validateNonNegativeInt("maxRetryCount", maxRetryCount)) {
return false;
@@ -161,12 +173,13 @@
if ((configStr.startsWith("\"") && configStr.endsWith("\""))) {
configStr = configStr.substring(1, configStr.length()-1);
}
- if (DBG) log("configure: '" + configStr + "'");
+ if (VDBG) log("configure: '" + configStr + "'");
+ mConfig = configStr;
if (!TextUtils.isEmpty(configStr)) {
int defaultRandomization = 0;
- if (DBG) log("configure: not empty");
+ if (VDBG) log("configure: not empty");
mMaxRetryCount = 0;
resetRetryCount();
@@ -174,14 +187,14 @@
String strArray[] = configStr.split(",");
for (int i = 0; i < strArray.length; i++) {
- if (DBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'");
+ if (VDBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'");
Pair<Boolean, Integer> value;
String splitStr[] = strArray[i].split("=", 2);
splitStr[0] = splitStr[0].trim();
- if (DBG) log("configure: splitStr[0]='" + splitStr[0] + "'");
+ if (VDBG) log("configure: splitStr[0]='" + splitStr[0] + "'");
if (splitStr.length > 1) {
splitStr[1] = splitStr[1].trim();
- if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
+ if (VDBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
if (TextUtils.equals(splitStr[0], "default_randomization")) {
value = parseNonNegativeInt(splitStr[0], splitStr[1]);
if (!value.first) return false;
@@ -214,7 +227,7 @@
// Check if optional randomization value present
if (splitStr.length > 1) {
splitStr[1] = splitStr[1].trim();
- if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
+ if (VDBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
value = parseNonNegativeInt("randomizationTime", splitStr[1]);
if (!value.first) return false;
rr.mRandomizationTime = value.second;
@@ -226,12 +239,12 @@
}
if (mRetryArray.size() > mMaxRetryCount) {
mMaxRetryCount = mRetryArray.size();
- if (DBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount);
+ if (VDBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount);
}
- if (DBG) log("configure: true");
+ if (VDBG) log("configure: true");
return true;
} else {
- if (DBG) log("configure: false it's empty");
+ if (VDBG) log("configure: false it's empty");
return false;
}
}
@@ -349,7 +362,7 @@
Log.e(LOG_TAG, name + " bad value: " + stringValue, e);
retVal = new Pair<Boolean, Integer>(false, 0);
}
- if (DBG) log("parseNonNetativeInt: " + name + ", " + stringValue + ", "
+ if (VDBG) log("parseNonNetativeInt: " + name + ", " + stringValue + ", "
+ retVal.first + ", " + retVal.second);
return retVal;
}
@@ -369,7 +382,7 @@
} else {
retVal = true;
}
- if (DBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal);
+ if (VDBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal);
return retVal;
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index e2579e3..f8d09de 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -1695,6 +1695,7 @@
@Override
protected void restartDataStallAlarm() {
+ if (isConnected() == false) return;
// To be called on screen status change.
// Do not cancel the alarm if it is set with aggressive timeout.
int nextAction = getRecoveryAction();
@@ -2141,10 +2142,9 @@
// clean slate after call end.
resetPollStats();
}
- } else {
- // reset reconnect timer
- setupDataOnReadyApns(Phone.REASON_VOICE_CALL_ENDED);
}
+ // reset reconnect timer
+ setupDataOnReadyApns(Phone.REASON_VOICE_CALL_ENDED);
}
@Override
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
index 414ae0d..0e75b80 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -210,28 +210,31 @@
glEnableVertexAttribArray(attribTexCoords);
checkGlError();
- glUniform1i(uniformTexture, texture);
+ glUniform1i(uniformTexture, 0);
+ checkGlError();
+
+ // drawQuad
+ triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+ glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+ checkGlError();
+
+ triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+ glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+ checkGlError();
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
checkGlError();
while (!mFinished) {
checkCurrent();
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- checkGlError();
-
glClear(GL_COLOR_BUFFER_BIT);
checkGlError();
- // drawQuad
- triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
- glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
- TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
-
- triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
- glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
- TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
-
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ checkGlError();
if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
throw new RuntimeException("Cannot swap buffers");
diff --git a/tests/RenderScriptTests/Balls/Android.mk b/tests/RenderScriptTests/Balls/Android.mk
new file mode 100644
index 0000000..b109584
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/Android.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := RsBalls
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/Balls/AndroidManifest.xml b/tests/RenderScriptTests/Balls/AndroidManifest.xml
new file mode 100644
index 0000000..80e6b39
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.rs.balls">
+ <uses-sdk android:minSdkVersion="14" />
+ <application
+ android:label="RsBalls"
+ android:icon="@drawable/test_pattern">
+ <activity android:name="Balls"
+ android:screenOrientation="landscape">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RenderScriptTests/Balls/_index.html b/tests/RenderScriptTests/Balls/_index.html
new file mode 100644
index 0000000..8760485
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/_index.html
@@ -0,0 +1 @@
+<p>A brute force physics simulation that renders many balls onto the screen and moves them according to user touch and gravity.</p>
\ No newline at end of file
diff --git a/tests/RenderScriptTests/Balls/res/drawable/flares.png b/tests/RenderScriptTests/Balls/res/drawable/flares.png
new file mode 100644
index 0000000..3a5c970
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/res/drawable/flares.png
Binary files differ
diff --git a/tests/RenderScriptTests/Balls/res/drawable/test_pattern.png b/tests/RenderScriptTests/Balls/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/res/drawable/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/Balls.java b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/Balls.java
new file mode 100644
index 0000000..2c6558e
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/Balls.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.balls;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
+public class Balls extends Activity implements SensorEventListener {
+ //EventListener mListener = new EventListener();
+
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = false;
+
+ private BallsView mView;
+ private SensorManager mSensorManager;
+
+ // get the current looper (from your Activity UI thread for instance
+
+
+ public void onSensorChanged(SensorEvent event) {
+ //android.util.Log.d("rs", "sensor: " + event.sensor + ", x: " + event.values[0] + ", y: " + event.values[1] + ", z: " + event.values[2]);
+ synchronized (this) {
+ if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+ if(mView != null) {
+ mView.setAccel(event.values[0], event.values[1], event.values[2]);
+ }
+ }
+ }
+ }
+
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new BallsView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ mSensorManager.registerListener(this,
+ mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
+ SensorManager.SENSOR_DELAY_FASTEST);
+
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mView.pause();
+ onStop();
+ }
+
+ @Override
+ protected void onStop() {
+ mSensorManager.unregisterListener(this);
+ super.onStop();
+ }
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
+ }
+
+
+}
+
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsRS.java b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsRS.java
new file mode 100644
index 0000000..8cab9b8
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsRS.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.balls;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+public class BallsRS {
+ public static final int PART_COUNT = 900;
+
+ public BallsRS() {
+ }
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ private ScriptC_balls mScript;
+ private ScriptC_ball_physics mPhysicsScript;
+ private ProgramFragment mPFLines;
+ private ProgramFragment mPFPoints;
+ private ProgramVertex mPV;
+ private ScriptField_Point mPoints;
+ private ScriptField_VpConsts mVpConsts;
+
+ void updateProjectionMatrices() {
+ mVpConsts = new ScriptField_VpConsts(mRS, 1,
+ Allocation.USAGE_SCRIPT |
+ Allocation.USAGE_GRAPHICS_CONSTANTS);
+ ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
+ Matrix4f mvp = new Matrix4f();
+ mvp.loadOrtho(0, mRS.getWidth(), mRS.getHeight(), 0, -1, 1);
+ i.MVP = mvp;
+ mVpConsts.set(i, 0, true);
+ }
+
+ private void createProgramVertex() {
+ updateProjectionMatrices();
+
+ ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS);
+ String t = "varying vec4 varColor;\n" +
+ "void main() {\n" +
+ " vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n" +
+ " pos.xy = ATTRIB_position;\n" +
+ " gl_Position = UNI_MVP * pos;\n" +
+ " varColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +
+ " gl_PointSize = ATTRIB_size;\n" +
+ "}\n";
+ sb.setShader(t);
+ sb.addConstant(mVpConsts.getType());
+ sb.addInput(mPoints.getElement());
+ ProgramVertex pvs = sb.create();
+ pvs.bindConstants(mVpConsts.getAllocation(), 0);
+ mRS.bindProgramVertex(pvs);
+ }
+
+ private Allocation loadTexture(int id) {
+ final Allocation allocation =
+ Allocation.createFromBitmapResource(mRS, mRes,
+ id, Allocation.MipmapControl.MIPMAP_NONE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
+ return allocation;
+ }
+
+ ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
+ ProgramStore.Builder builder = new ProgramStore.Builder(rs);
+ builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+ builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
+ builder.setDitherEnabled(false);
+ builder.setDepthMaskEnabled(false);
+ return builder.create();
+ }
+
+ public void init(RenderScriptGL rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+
+ ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+ pfb.setPointSpriteTexCoordinateReplacement(true);
+ pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
+ ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+ pfb.setVaryingColor(true);
+ mPFPoints = pfb.create();
+
+ pfb = new ProgramFragmentFixedFunction.Builder(rs);
+ pfb.setVaryingColor(true);
+ mPFLines = pfb.create();
+
+ android.util.Log.e("rs", "Load texture");
+ mPFPoints.bindTexture(loadTexture(R.drawable.flares), 0);
+
+ mPoints = new ScriptField_Point(mRS, PART_COUNT, Allocation.USAGE_SCRIPT);
+
+ Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+ smb.addVertexAllocation(mPoints.getAllocation());
+ smb.addIndexSetType(Mesh.Primitive.POINT);
+ Mesh smP = smb.create();
+
+ mPhysicsScript = new ScriptC_ball_physics(mRS, mRes, R.raw.ball_physics);
+
+ mScript = new ScriptC_balls(mRS, mRes, R.raw.balls);
+ mScript.set_partMesh(smP);
+ mScript.set_physics_script(mPhysicsScript);
+ mScript.bind_point(mPoints);
+ mScript.bind_balls1(new ScriptField_Ball(mRS, PART_COUNT, Allocation.USAGE_SCRIPT));
+ mScript.bind_balls2(new ScriptField_Ball(mRS, PART_COUNT, Allocation.USAGE_SCRIPT));
+
+ mScript.set_gPFLines(mPFLines);
+ mScript.set_gPFPoints(mPFPoints);
+ createProgramVertex();
+
+ mRS.bindProgramStore(BLEND_ADD_DEPTH_NONE(mRS));
+
+ mPhysicsScript.set_gMinPos(new Float2(5, 5));
+ mPhysicsScript.set_gMaxPos(new Float2(width - 5, height - 5));
+
+ mScript.invoke_initParts(width, height);
+
+ mRS.bindRootScript(mScript);
+ }
+
+ public void newTouchPosition(float x, float y, float pressure, int id) {
+ mPhysicsScript.invoke_touch(x, y, pressure, id);
+ }
+
+ public void setAccel(float x, float y) {
+ mPhysicsScript.set_gGravityVector(new Float2(x, y));
+ }
+
+}
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java
new file mode 100644
index 0000000..b3b3756
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.balls;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class BallsView extends RSSurfaceView {
+
+ public BallsView(Context context) {
+ super(context);
+ //setFocusable(true);
+ }
+
+ private RenderScriptGL mRS;
+ private BallsRS mRender;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+ if (mRS == null) {
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ mRS = createRenderScriptGL(sc);
+ mRS.setSurface(holder, w, h);
+ mRender = new BallsRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+ mRender.updateProjectionMatrices();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if(mRS != null) {
+ mRS = null;
+ destroyRenderScriptGL();
+ }
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ int act = ev.getActionMasked();
+ if (act == ev.ACTION_UP) {
+ mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
+ return false;
+ } else if (act == MotionEvent.ACTION_POINTER_UP) {
+ // only one pointer going up, we can get the index like this
+ int pointerIndex = ev.getActionIndex();
+ int pointerId = ev.getPointerId(pointerIndex);
+ mRender.newTouchPosition(0, 0, 0, pointerId);
+ return false;
+ }
+ int count = ev.getHistorySize();
+ int pcount = ev.getPointerCount();
+
+ for (int p=0; p < pcount; p++) {
+ int id = ev.getPointerId(p);
+ mRender.newTouchPosition(ev.getX(p),
+ ev.getY(p),
+ ev.getPressure(p),
+ id);
+
+ for (int i=0; i < count; i++) {
+ mRender.newTouchPosition(ev.getHistoricalX(p, i),
+ ev.getHistoricalY(p, i),
+ ev.getHistoricalPressure(p, i),
+ id);
+ }
+ }
+ return true;
+ }
+
+ void setAccel(float x, float y, float z) {
+ if (mRender == null) {
+ return;
+ }
+ mRender.setAccel(x, -y);
+ }
+
+}
+
+
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/ball_physics.rs b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/ball_physics.rs
new file mode 100644
index 0000000..8a3db6d
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/ball_physics.rs
@@ -0,0 +1,146 @@
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.balls)
+
+#include "balls.rsh"
+
+float2 gGravityVector = {0.f, 9.8f};
+
+float2 gMinPos = {0.f, 0.f};
+float2 gMaxPos = {1280.f, 700.f};
+
+static float2 touchPos[10];
+static float touchPressure[10];
+
+void touch(float x, float y, float pressure, int id) {
+ if (id >= 10) {
+ return;
+ }
+
+ touchPos[id].x = x;
+ touchPos[id].y = y;
+ touchPressure[id] = pressure;
+}
+
+void root(const Ball_t *ballIn, Ball_t *ballOut, const BallControl_t *ctl, uint32_t x) {
+ float2 fv = {0, 0};
+ float2 pos = ballIn->position;
+
+ int arcID = -1;
+ float arcInvStr = 100000;
+
+ const Ball_t * bPtr = rsGetElementAt(ctl->ain, 0);
+ for (uint32_t xin = 0; xin < ctl->dimX; xin++) {
+ float2 vec = bPtr[xin].position - pos;
+ float2 vec2 = vec * vec;
+ float len2 = vec2.x + vec2.y;
+
+ if (len2 < 10000) {
+ //float minDist = ballIn->size + bPtr[xin].size;
+ float forceScale = ballIn->size * bPtr[xin].size;
+ forceScale *= forceScale;
+
+ if (len2 > 16 /* (minDist*minDist)*/) {
+ // Repulsion
+ float len = sqrt(len2);
+ fv -= (vec / (len * len * len)) * 20000.f * forceScale;
+ } else {
+ if (len2 < 1) {
+ if (xin == x) {
+ continue;
+ }
+ ballOut->delta = 0.f;
+ ballOut->position = ballIn->position;
+ if (xin > x) {
+ ballOut->position.x += 1.f;
+ } else {
+ ballOut->position.x -= 1.f;
+ }
+ //ballOut->color.rgb = 1.f;
+ //ballOut->arcID = -1;
+ //ballOut->arcStr = 0;
+ continue;
+ }
+ // Collision
+ float2 axis = normalize(vec);
+ float e1 = dot(axis, ballIn->delta);
+ float e2 = dot(axis, bPtr[xin].delta);
+ float e = (e1 - e2) * 0.45f;
+ if (e1 > 0) {
+ fv -= axis * e;
+ } else {
+ fv += axis * e;
+ }
+ }
+ }
+ }
+
+ fv /= ballIn->size * ballIn->size * ballIn->size;
+ fv -= gGravityVector * 4.f;
+ fv *= ctl->dt;
+
+ for (int i=0; i < 10; i++) {
+ if (touchPressure[i] > 0.1f) {
+ float2 vec = touchPos[i] - ballIn->position;
+ float2 vec2 = vec * vec;
+ float len2 = max(2.f, vec2.x + vec2.y);
+ fv -= (vec / len2) * touchPressure[i] * 300.f;
+ }
+ }
+
+ ballOut->delta = (ballIn->delta * (1.f - 0.004f)) + fv;
+ ballOut->position = ballIn->position + (ballOut->delta * ctl->dt);
+
+ const float wallForce = 400.f;
+ if (ballOut->position.x > (gMaxPos.x - 20.f)) {
+ float d = gMaxPos.x - ballOut->position.x;
+ if (d < 0.f) {
+ if (ballOut->delta.x > 0) {
+ ballOut->delta.x *= -0.7f;
+ }
+ ballOut->position.x = gMaxPos.x;
+ } else {
+ ballOut->delta.x -= min(wallForce / (d * d), 10.f);
+ }
+ }
+
+ if (ballOut->position.x < (gMinPos.x + 20.f)) {
+ float d = ballOut->position.x - gMinPos.x;
+ if (d < 0.f) {
+ if (ballOut->delta.x < 0) {
+ ballOut->delta.x *= -0.7f;
+ }
+ ballOut->position.x = gMinPos.x + 1.f;
+ } else {
+ ballOut->delta.x += min(wallForce / (d * d), 10.f);
+ }
+ }
+
+ if (ballOut->position.y > (gMaxPos.y - 20.f)) {
+ float d = gMaxPos.y - ballOut->position.y;
+ if (d < 0.f) {
+ if (ballOut->delta.y > 0) {
+ ballOut->delta.y *= -0.7f;
+ }
+ ballOut->position.y = gMaxPos.y;
+ } else {
+ ballOut->delta.y -= min(wallForce / (d * d), 10.f);
+ }
+ }
+
+ if (ballOut->position.y < (gMinPos.y + 20.f)) {
+ float d = ballOut->position.y - gMinPos.y;
+ if (d < 0.f) {
+ if (ballOut->delta.y < 0) {
+ ballOut->delta.y *= -0.7f;
+ }
+ ballOut->position.y = gMinPos.y + 1.f;
+ } else {
+ ballOut->delta.y += min(wallForce / (d * d * d), 10.f);
+ }
+ }
+
+ ballOut->size = ballIn->size;
+
+ //rsDebug("physics pos out", ballOut->position);
+}
+
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rs b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rs
new file mode 100644
index 0000000..dcdd586
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rs
@@ -0,0 +1,83 @@
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.balls)
+#include "rs_graphics.rsh"
+
+#include "balls.rsh"
+
+#pragma stateVertex(parent)
+#pragma stateStore(parent)
+
+rs_program_fragment gPFPoints;
+rs_program_fragment gPFLines;
+rs_mesh partMesh;
+
+typedef struct __attribute__((packed, aligned(4))) Point {
+ float2 position;
+ float size;
+} Point_t;
+Point_t *point;
+
+typedef struct VpConsts {
+ rs_matrix4x4 MVP;
+} VpConsts_t;
+VpConsts_t *vpConstants;
+
+rs_script physics_script;
+
+Ball_t *balls1;
+Ball_t *balls2;
+
+static int frame = 0;
+
+void initParts(int w, int h)
+{
+ uint32_t dimX = rsAllocationGetDimX(rsGetAllocation(balls1));
+
+ for (uint32_t ct=0; ct < dimX; ct++) {
+ balls1[ct].position.x = rsRand(0.f, (float)w);
+ balls1[ct].position.y = rsRand(0.f, (float)h);
+ balls1[ct].delta.x = 0.f;
+ balls1[ct].delta.y = 0.f;
+ balls1[ct].size = 1.f;
+
+ float r = rsRand(100.f);
+ if (r > 90.f) {
+ balls1[ct].size += pow(10.f, rsRand(0.f, 2.f)) * 0.07f;
+ }
+ }
+}
+
+
+
+int root() {
+ rsgClearColor(0.f, 0.f, 0.f, 1.f);
+
+ BallControl_t bc;
+ Ball_t *bout;
+
+ if (frame & 1) {
+ bc.ain = rsGetAllocation(balls2);
+ bc.aout = rsGetAllocation(balls1);
+ bout = balls1;
+ } else {
+ bc.ain = rsGetAllocation(balls1);
+ bc.aout = rsGetAllocation(balls2);
+ bout = balls2;
+ }
+
+ bc.dimX = rsAllocationGetDimX(bc.ain);
+ bc.dt = 1.f / 30.f;
+
+ rsForEach(physics_script, bc.ain, bc.aout, &bc, sizeof(bc));
+
+ for (uint32_t ct=0; ct < bc.dimX; ct++) {
+ point[ct].position = bout[ct].position;
+ point[ct].size = 6.f /*+ bout[ct].color.g * 6.f*/ * bout[ct].size;
+ }
+
+ frame++;
+ rsgBindProgramFragment(gPFPoints);
+ rsgDrawMesh(partMesh);
+ return 1;
+}
+
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rsh b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rsh
new file mode 100644
index 0000000..fc886f9
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rsh
@@ -0,0 +1,18 @@
+
+typedef struct __attribute__((packed, aligned(4))) Ball {
+ float2 delta;
+ float2 position;
+ //float3 color;
+ float size;
+ //int arcID;
+ //float arcStr;
+} Ball_t;
+Ball_t *balls;
+
+
+typedef struct BallControl {
+ uint32_t dimX;
+ rs_allocation ain;
+ rs_allocation aout;
+ float dt;
+} BallControl_t;
diff --git a/tests/RenderScriptTests/Fountain/Android.mk b/tests/RenderScriptTests/Fountain/Android.mk
new file mode 100644
index 0000000..2049ecf
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+# TODO: build fails with this set
+# LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := RsFountain
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/Fountain/AndroidManifest.xml b/tests/RenderScriptTests/Fountain/AndroidManifest.xml
new file mode 100644
index 0000000..d19b8c3
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.rs.fountain">
+ <uses-sdk android:minSdkVersion="14" />
+ <application
+ android:label="RsFountain"
+ android:hardwareAccelerated="true"
+ android:icon="@drawable/test_pattern">
+ <activity android:name="Fountain">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RenderScriptTests/Fountain/_index.html b/tests/RenderScriptTests/Fountain/_index.html
new file mode 100644
index 0000000..223242f
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/_index.html
@@ -0,0 +1,5 @@
+<p>An example that renders many dots on the screen that follow a user's touch. The dots fall
+to the bottom of the screen when the user releases the finger.</p>
+
+
+
diff --git a/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png b/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java
new file mode 100644
index 0000000..311455a
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.fountain;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+public class Fountain extends Activity {
+ //EventListener mListener = new EventListener();
+
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = false;
+
+ private FountainView mView;
+
+ // get the current looper (from your Activity UI thread for instance
+
+
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new FountainView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ Log.e("rs", "onResume");
+
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ Log.e("rs", "onPause");
+
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.pause();
+
+
+
+ //Runtime.getRuntime().exit(0);
+ }
+
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
+ }
+
+
+}
+
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java
new file mode 100644
index 0000000..646c807
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.fountain;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+
+public class FountainRS {
+ public static final int PART_COUNT = 50000;
+
+ public FountainRS() {
+ }
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ private ScriptC_fountain mScript;
+ public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+
+ ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+ pfb.setVaryingColor(true);
+ rs.bindProgramFragment(pfb.create());
+
+ ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);//
+ // Allocation.USAGE_GRAPHICS_VERTEX);
+
+ Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+ smb.addVertexAllocation(points.getAllocation());
+ smb.addIndexSetType(Mesh.Primitive.POINT);
+ Mesh sm = smb.create();
+
+ mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain);
+ mScript.set_partMesh(sm);
+ mScript.bind_point(points);
+ mRS.bindRootScript(mScript);
+ }
+
+ boolean holdingColor[] = new boolean[10];
+ public void newTouchPosition(float x, float y, float pressure, int id) {
+ if (id >= holdingColor.length) {
+ return;
+ }
+ int rate = (int)(pressure * pressure * 500.f);
+ if (rate > 500) {
+ rate = 500;
+ }
+ if (rate > 0) {
+ mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]);
+ holdingColor[id] = true;
+ } else {
+ holdingColor[id] = false;
+ }
+
+ }
+}
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java
new file mode 100644
index 0000000..ba09421
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.fountain;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSTextureView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class FountainView extends RSTextureView {
+
+ public FountainView(Context context) {
+ super(context);
+ //setFocusable(true);
+ }
+
+ private RenderScriptGL mRS;
+ private FountainRS mRender;
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ android.util.Log.e("rs", "onAttachedToWindow");
+ if (mRS == null) {
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ mRS = createRenderScriptGL(sc);
+ mRender = new FountainRS();
+ mRender.init(mRS, getResources());
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ android.util.Log.e("rs", "onDetachedFromWindow");
+ if (mRS != null) {
+ mRS = null;
+ destroyRenderScriptGL();
+ }
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ int act = ev.getActionMasked();
+ if (act == ev.ACTION_UP) {
+ mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
+ return false;
+ } else if (act == MotionEvent.ACTION_POINTER_UP) {
+ // only one pointer going up, we can get the index like this
+ int pointerIndex = ev.getActionIndex();
+ int pointerId = ev.getPointerId(pointerIndex);
+ mRender.newTouchPosition(0, 0, 0, pointerId);
+ }
+ int count = ev.getHistorySize();
+ int pcount = ev.getPointerCount();
+
+ for (int p=0; p < pcount; p++) {
+ int id = ev.getPointerId(p);
+ mRender.newTouchPosition(ev.getX(p),
+ ev.getY(p),
+ ev.getPressure(p),
+ id);
+
+ for (int i=0; i < count; i++) {
+ mRender.newTouchPosition(ev.getHistoricalX(p, i),
+ ev.getHistoricalY(p, i),
+ ev.getHistoricalPressure(p, i),
+ id);
+ }
+ }
+ return true;
+ }
+}
+
+
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs
new file mode 100644
index 0000000..151b689
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs
@@ -0,0 +1,70 @@
+// Fountain test script
+#pragma version(1)
+#pragma rs_fp_relaxed
+
+#pragma rs java_package_name(com.example.android.rs.fountain)
+
+#pragma stateFragment(parent)
+
+#include "rs_graphics.rsh"
+
+static int newPart = 0;
+rs_mesh partMesh;
+
+typedef struct __attribute__((packed, aligned(4))) Point {
+ float2 delta;
+ float2 position;
+ uchar4 color;
+} Point_t;
+Point_t *point;
+
+int root() {
+ float dt = min(rsGetDt(), 0.1f);
+ rsgClearColor(0.f, 0.f, 0.f, 1.f);
+ const float height = rsgGetHeight();
+ const int size = rsAllocationGetDimX(rsGetAllocation(point));
+ float dy2 = dt * (10.f);
+ Point_t * p = point;
+ for (int ct=0; ct < size; ct++) {
+ p->delta.y += dy2;
+ p->position += p->delta;
+ if ((p->position.y > height) && (p->delta.y > 0)) {
+ p->delta.y *= -0.3f;
+ }
+ p++;
+ }
+
+ rsgDrawMesh(partMesh);
+ return 1;
+}
+
+static float4 partColor[10];
+void addParticles(int rate, float x, float y, int index, bool newColor)
+{
+ if (newColor) {
+ partColor[index].x = rsRand(0.5f, 1.0f);
+ partColor[index].y = rsRand(1.0f);
+ partColor[index].z = rsRand(1.0f);
+ }
+ float rMax = ((float)rate) * 0.02f;
+ int size = rsAllocationGetDimX(rsGetAllocation(point));
+ uchar4 c = rsPackColorTo8888(partColor[index]);
+
+ Point_t * np = &point[newPart];
+ float2 p = {x, y};
+ while (rate--) {
+ float angle = rsRand(3.14f * 2.f);
+ float len = rsRand(rMax);
+ np->delta.x = len * sin(angle);
+ np->delta.y = len * cos(angle);
+ np->position = p;
+ np->color = c;
+ newPart++;
+ np++;
+ if (newPart >= size) {
+ newPart = 0;
+ np = &point[newPart];
+ }
+ }
+}
+
diff --git a/tests/RenderScriptTests/FountainFbo/Android.mk b/tests/RenderScriptTests/FountainFbo/Android.mk
new file mode 100644
index 0000000..55a4fd8
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+# TODO: build fails with this set
+# LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := RsFountainFbo
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml b/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml
new file mode 100644
index 0000000..082744b
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.rs.fountainfbo">
+ <uses-sdk android:minSdkVersion="14" />
+ <application
+ android:label="RsFountainFbo"
+ android:hardwareAccelerated="true"
+ android:icon="@drawable/test_pattern">
+ <activity android:name="FountainFbo">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RenderScriptTests/FountainFbo/_index.html b/tests/RenderScriptTests/FountainFbo/_index.html
new file mode 100644
index 0000000..5508657
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/_index.html
@@ -0,0 +1,7 @@
+<p>An example that renders many dots on the screen that follow a user's touch. The dots fall
+to the bottom of the screen when no touch is detected. This example modifies
+the <a href="../Fountain/index.html">Fountain</a> sample to include rendering to a
+a framebuffer object as well as the default framebuffer.</p>
+
+
+
diff --git a/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png b/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java
new file mode 100644
index 0000000..d8ba30fd
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.fountainfbo;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class FountainFbo extends Activity {
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = false;
+
+ private FountainFboView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ /* Create our Preview view and set it as the content of our Activity */
+ mView = new FountainFboView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ Log.e("rs", "onResume");
+
+ /* Ideally a game should implement onResume() and onPause()
+ to take appropriate action when the activity loses focus */
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ Log.e("rs", "onPause");
+
+ /* Ideally a game should implement onResume() and onPause()
+ to take appropriate action when the activity loses focus */
+ super.onPause();
+ mView.pause();
+ }
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
+ }
+}
+
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java
new file mode 100644
index 0000000..3bf3ff1
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.fountainfbo;
+
+import android.content.res.Resources;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Mesh;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramFragmentFixedFunction;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Type;
+
+public class FountainFboRS {
+ public static final int PART_COUNT = 50000;
+
+ public FountainFboRS() {
+ }
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ private ScriptC_fountainfbo mScript;
+ private Allocation mColorBuffer;
+ private ProgramFragment mProgramFragment;
+ private ProgramFragment mTextureProgramFragment;
+ public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+
+ ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);
+
+ Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+ smb.addVertexAllocation(points.getAllocation());
+ smb.addIndexSetType(Mesh.Primitive.POINT);
+ Mesh sm = smb.create();
+
+ mScript = new ScriptC_fountainfbo(mRS, mRes, R.raw.fountainfbo);
+ mScript.set_partMesh(sm);
+ mScript.bind_point(points);
+
+ ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+ pfb.setVaryingColor(true);
+ mProgramFragment = pfb.create();
+ mScript.set_gProgramFragment(mProgramFragment);
+
+ /* Second fragment shader to use a texture (framebuffer object) to draw with */
+ pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+ ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+
+ /* Set the fragment shader in the Renderscript runtime */
+ mTextureProgramFragment = pfb.create();
+ mScript.set_gTextureProgramFragment(mTextureProgramFragment);
+
+ /* Create the allocation for the color buffer */
+ Type.Builder colorBuilder = new Type.Builder(mRS, Element.RGBA_8888(mRS));
+ colorBuilder.setX(256).setY(256);
+ mColorBuffer = Allocation.createTyped(mRS, colorBuilder.create(),
+ Allocation.USAGE_GRAPHICS_TEXTURE |
+ Allocation.USAGE_GRAPHICS_RENDER_TARGET);
+
+ /* Set the allocation in the Renderscript runtime */
+ mScript.set_gColorBuffer(mColorBuffer);
+
+ mRS.bindRootScript(mScript);
+ }
+
+ boolean holdingColor[] = new boolean[10];
+ public void newTouchPosition(float x, float y, float pressure, int id) {
+ if (id >= holdingColor.length) {
+ return;
+ }
+ int rate = (int)(pressure * pressure * 500.f);
+ if (rate > 500) {
+ rate = 500;
+ }
+ if (rate > 0) {
+ mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]);
+ holdingColor[id] = true;
+ } else {
+ holdingColor[id] = false;
+ }
+
+ }
+}
+
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java
new file mode 100644
index 0000000..6e40da3
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.fountainfbo;
+
+
+import android.renderscript.RSTextureView;
+import android.renderscript.RenderScriptGL;
+import android.content.Context;
+import android.view.MotionEvent;
+
+public class FountainFboView extends RSTextureView {
+
+ public FountainFboView(Context context) {
+ super(context);
+ }
+
+ private RenderScriptGL mRS;
+ private FountainFboRS mRender;
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ android.util.Log.e("rs", "onAttachedToWindow");
+ if (mRS == null) {
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ mRS = createRenderScriptGL(sc);
+ mRender = new FountainFboRS();
+ mRender.init(mRS, getResources());
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ android.util.Log.e("rs", "onDetachedFromWindow");
+ if (mRS != null) {
+ mRS = null;
+ destroyRenderScriptGL();
+ }
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ int act = ev.getActionMasked();
+ if (act == ev.ACTION_UP) {
+ mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
+ return false;
+ } else if (act == MotionEvent.ACTION_POINTER_UP) {
+ // only one pointer going up, we can get the index like this
+ int pointerIndex = ev.getActionIndex();
+ int pointerId = ev.getPointerId(pointerIndex);
+ mRender.newTouchPosition(0, 0, 0, pointerId);
+ }
+ int count = ev.getHistorySize();
+ int pcount = ev.getPointerCount();
+
+ for (int p=0; p < pcount; p++) {
+ int id = ev.getPointerId(p);
+ mRender.newTouchPosition(ev.getX(p),
+ ev.getY(p),
+ ev.getPressure(p),
+ id);
+
+ for (int i=0; i < count; i++) {
+ mRender.newTouchPosition(ev.getHistoricalX(p, i),
+ ev.getHistoricalY(p, i),
+ ev.getHistoricalPressure(p, i),
+ id);
+ }
+ }
+ return true;
+ }
+}
+
+
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs
new file mode 100644
index 0000000..763f6ba
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs
@@ -0,0 +1,106 @@
+// Fountain test script
+#pragma version(1)
+
+#pragma rs java_package_name(com.example.android.rs.fountainfbo)
+
+#pragma stateFragment(parent)
+
+#include "rs_graphics.rsh"
+
+static int newPart = 0;
+rs_mesh partMesh;
+rs_program_vertex gProgramVertex;
+
+//allocation for color buffer
+rs_allocation gColorBuffer;
+//fragment shader for rendering without a texture (used for rendering to framebuffer object)
+rs_program_fragment gProgramFragment;
+//fragment shader for rendering with a texture (used for rendering to default framebuffer)
+rs_program_fragment gTextureProgramFragment;
+
+typedef struct __attribute__((packed, aligned(4))) Point {
+ float2 delta;
+ float2 position;
+ uchar4 color;
+} Point_t;
+Point_t *point;
+
+int root() {
+ float dt = min(rsGetDt(), 0.1f);
+ rsgClearColor(0.f, 0.f, 0.f, 1.f);
+ const float height = rsgGetHeight();
+ const int size = rsAllocationGetDimX(rsGetAllocation(point));
+ float dy2 = dt * (10.f);
+ Point_t * p = point;
+ for (int ct=0; ct < size; ct++) {
+ p->delta.y += dy2;
+ p->position += p->delta;
+ if ((p->position.y > height) && (p->delta.y > 0)) {
+ p->delta.y *= -0.3f;
+ }
+ p++;
+ }
+ //Tell Renderscript runtime to render to the frame buffer object
+ rsgBindColorTarget(gColorBuffer, 0);
+
+ //Begin rendering on a white background
+ rsgClearColor(1.f, 1.f, 1.f, 1.f);
+ rsgDrawMesh(partMesh);
+
+ //When done, tell Renderscript runtime to stop rendering to framebuffer object
+ rsgClearAllRenderTargets();
+
+ //Bind a new fragment shader that declares the framebuffer object to be used as a texture
+ rsgBindProgramFragment(gTextureProgramFragment);
+
+ //Bind the framebuffer object to the fragment shader at slot 0 as a texture
+ rsgBindTexture(gTextureProgramFragment, 0, gColorBuffer);
+
+ //Draw a quad using the framebuffer object as the texture
+ float startX = 10, startY = 10;
+ float s = 256;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
+ startX, startY + s, 0, 0, 0,
+ startX + s, startY + s, 0, 1, 0,
+ startX + s, startY, 0, 1, 1);
+
+ //Rebind the original fragment shader to render as normal
+ rsgBindProgramFragment(gProgramFragment);
+
+ //Render the main scene
+ rsgDrawMesh(partMesh);
+
+ return 1;
+}
+
+static float4 partColor[10];
+void addParticles(int rate, float x, float y, int index, bool newColor)
+{
+ if (newColor) {
+ partColor[index].x = rsRand(0.5f, 1.0f);
+ partColor[index].y = rsRand(1.0f);
+ partColor[index].z = rsRand(1.0f);
+ }
+ float rMax = ((float)rate) * 0.02f;
+ int size = rsAllocationGetDimX(rsGetAllocation(point));
+ uchar4 c = rsPackColorTo8888(partColor[index]);
+
+ Point_t * np = &point[newPart];
+ float2 p = {x, y};
+ while (rate--) {
+ float angle = rsRand(3.14f * 2.f);
+ float len = rsRand(rMax);
+ np->delta.x = len * sin(angle);
+ np->delta.y = len * cos(angle);
+ np->position = p;
+ np->color = c;
+ newPart++;
+ np++;
+ if (newPart >= size) {
+ newPart = 0;
+ np = &point[newPart];
+ }
+ }
+}
+
+
diff --git a/tests/RenderScriptTests/HelloWorld/Android.mk b/tests/RenderScriptTests/HelloWorld/Android.mk
new file mode 100644
index 0000000..2af1cdb
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := RsHelloWorld
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml b/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml
new file mode 100644
index 0000000..1d37dc9
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.rs.helloworld">
+ <uses-sdk android:minSdkVersion="11" />
+ <application android:label="RsHelloWorld"
+ android:icon="@drawable/test_pattern">
+ <activity android:name="HelloWorld"
+ android:label="RsHelloWorld"
+ android:theme="@android:style/Theme.Black.NoTitleBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RenderScriptTests/HelloWorld/_index.html b/tests/RenderScriptTests/HelloWorld/_index.html
new file mode 100644
index 0000000..4cab738
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/_index.html
@@ -0,0 +1 @@
+<p>A Renderscript graphics application that draws the text "Hello, World!" where the user touches.</p>
\ No newline at end of file
diff --git a/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png b/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java
new file mode 100644
index 0000000..9b1697b
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.helloworld;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+// Renderscript activity
+public class HelloWorld extends Activity {
+
+ // Custom view to use with RenderScript
+ private HelloWorldView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our view and set it as the content of our Activity
+ mView = new HelloWorldView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally an app should implement onResume() and onPause()
+ // to take appropriate action when the activity loses focus
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally an app should implement onResume() and onPause()
+ // to take appropriate action when the activity loses focus
+ super.onPause();
+ mView.pause();
+ }
+
+}
+
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java
new file mode 100644
index 0000000..4316411
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.helloworld;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+
+// This is the renderer for the HelloWorldView
+public class HelloWorldRS {
+ private Resources mRes;
+ private RenderScriptGL mRS;
+
+ private ScriptC_helloworld mScript;
+
+ public HelloWorldRS() {
+ }
+
+ // This provides us with the renderscript context and resources that
+ // allow us to create the script that does rendering
+ public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+ initRS();
+ }
+
+ public void onActionDown(int x, int y) {
+ mScript.set_gTouchX(x);
+ mScript.set_gTouchY(y);
+ }
+
+ private void initRS() {
+ mScript = new ScriptC_helloworld(mRS, mRes, R.raw.helloworld);
+ mRS.bindRootScript(mScript);
+ }
+}
+
+
+
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java
new file mode 100644
index 0000000..557ebc5
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.helloworld;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.view.MotionEvent;
+
+public class HelloWorldView extends RSSurfaceView {
+ // Renderscipt context
+ private RenderScriptGL mRS;
+ // Script that does the rendering
+ private HelloWorldRS mRender;
+
+ public HelloWorldView(Context context) {
+ super(context);
+ ensureRenderScript();
+ }
+
+ private void ensureRenderScript() {
+ if (mRS == null) {
+ // Initialize renderscript with desired surface characteristics.
+ // In this case, just use the defaults
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ mRS = createRenderScriptGL(sc);
+ // Create an instance of the script that does the rendering
+ mRender = new HelloWorldRS();
+ mRender.init(mRS, getResources());
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ ensureRenderScript();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ // Handle the system event and clean up
+ mRender = null;
+ if (mRS != null) {
+ mRS = null;
+ destroyRenderScriptGL();
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ // Pass touch events from the system to the rendering script
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mRender.onActionDown((int)ev.getX(), (int)ev.getY());
+ return true;
+ }
+
+ return false;
+ }
+}
+
+
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs
new file mode 100644
index 0000000..bcf624e
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs
@@ -0,0 +1,47 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+// Tell which java package name the reflected files should belong to
+#pragma rs java_package_name(com.example.android.rs.helloworld)
+
+// Built-in header with graphics API's
+#include "rs_graphics.rsh"
+
+// gTouchX and gTouchY are variables that will be reflected for use
+// by the java API. We can use them to notify the script of touch events.
+int gTouchX;
+int gTouchY;
+
+// This is invoked automatically when the script is created
+void init() {
+ gTouchX = 50.0f;
+ gTouchY = 50.0f;
+}
+
+int root(void) {
+
+ // Clear the background color
+ rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ // Tell the runtime what the font color should be
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ // Introuduce ourselves to the world by drawing a greeting
+ // at the position user touched on the screen
+ rsgDrawText("Hello World!", gTouchX, gTouchY);
+
+ // Return value tells RS roughly how often to redraw
+ // in this case 20 ms
+ return 20;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/Android.mk b/tests/RenderScriptTests/MiscSamples/Android.mk
new file mode 100644
index 0000000..6b8b691
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := RsMiscSamples
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml b/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml
new file mode 100644
index 0000000..08a3976
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.rs.miscsamples">
+ <uses-sdk android:minSdkVersion="11" />
+ <application android:label="RsMiscSamples"
+ android:icon="@drawable/test_pattern">
+ <activity android:name="RsList"
+ android:label="RsList"
+ android:theme="@android:style/Theme.Black.NoTitleBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="RsRenderStates"
+ android:label="RsStates"
+ android:theme="@android:style/Theme.Black.NoTitleBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RenderScriptTests/MiscSamples/_index.html b/tests/RenderScriptTests/MiscSamples/_index.html
new file mode 100644
index 0000000..5872431
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/_index.html
@@ -0,0 +1 @@
+<p>A set of samples that demonstrate how to use various features of the Renderscript APIs.</p>
\ No newline at end of file
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png
new file mode 100644
index 0000000..b631e1e
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png
new file mode 100644
index 0000000..baf35d0
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png
new file mode 100644
index 0000000..8e34714
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png
new file mode 100644
index 0000000..3cd3775
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png
new file mode 100644
index 0000000..1e08f3b
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl
new file mode 100644
index 0000000..e492a47
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl
@@ -0,0 +1,13 @@
+varying vec2 varTex0;
+
+void main() {
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col0 = texture2D(UNI_Tex0, t0).rgba;
+ lowp vec4 col1 = texture2D(UNI_Tex1, t0*4.0).rgba;
+ lowp vec4 col2 = texture2D(UNI_Tex2, t0).rgba;
+ col0.xyz = col0.xyz*col1.xyz*1.5;
+ col0.xyz = mix(col0.xyz, col2.xyz, col2.w);
+ col0.w = 0.5;
+ gl_FragColor = col0;
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl
new file mode 100644
index 0000000..5fc05f1
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl
@@ -0,0 +1,29 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(-varWorldPos.xyz);
+ vec3 worldNorm = normalize(varWorldNormal);
+
+ vec3 light0Vec = normalize(UNI_light0_Posision.xyz - varWorldPos);
+ vec3 light0R = -reflect(light0Vec, worldNorm);
+ float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse;
+ float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
+ float light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular;
+
+ vec3 light1Vec = normalize(UNI_light1_Posision.xyz - varWorldPos);
+ vec3 light1R = reflect(light1Vec, worldNorm);
+ float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse;
+ float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
+ float light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular;
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz);
+ col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz;
+ col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz;
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl
new file mode 100644
index 0000000..a2c807e
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl
@@ -0,0 +1,21 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+ vec4 objPos = ATTRIB_position;
+ vec3 oldPos = objPos.xyz;
+ objPos.xyz += 0.1*sin(objPos.xyz*2.0 + UNI_time);
+ objPos.xyz += 0.05*sin(objPos.xyz*4.0 + UNI_time*0.5);
+ objPos.xyz += 0.02*sin(objPos.xyz*7.0 + UNI_time*0.75);
+ vec4 worldPos = UNI_model * objPos;
+ gl_Position = UNI_proj * worldPos;
+
+ mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+ vec3 worldNorm = model3 * (ATTRIB_normal + oldPos - objPos.xyz);
+
+ varWorldPos = worldPos.xyz;
+ varWorldNormal = worldNorm;
+ varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl
new file mode 100644
index 0000000..e6885a3
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl
@@ -0,0 +1,17 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+ vec4 objPos = ATTRIB_position;
+ vec4 worldPos = UNI_model * objPos;
+ gl_Position = UNI_proj * worldPos;
+
+ mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+ vec3 worldNorm = model3 * ATTRIB_normal;
+
+ varWorldPos = worldPos.xyz;
+ varWorldNormal = worldNorm;
+ varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl
new file mode 100644
index 0000000..238ecad
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl
@@ -0,0 +1,16 @@
+
+varying lowp float light0_Diffuse;
+varying lowp float light0_Specular;
+varying lowp float light1_Diffuse;
+varying lowp float light1_Specular;
+varying vec2 varTex0;
+
+void main() {
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * (light0_Diffuse * UNI_light_DiffuseColor[0].xyz + light1_Diffuse * UNI_light_DiffuseColor[1].xyz);
+ col.xyz += light0_Specular * UNI_light_SpecularColor[0].xyz;
+ col.xyz += light1_Specular * UNI_light_SpecularColor[1].xyz;
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl
new file mode 100644
index 0000000..7a1310a
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl
@@ -0,0 +1,32 @@
+varying float light0_Diffuse;
+varying float light0_Specular;
+varying float light1_Diffuse;
+varying float light1_Specular;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+ vec4 worldPos = UNI_model[0] * ATTRIB_position;
+ worldPos = UNI_model[1] * worldPos;
+ gl_Position = UNI_proj * worldPos;
+
+ mat4 model0 = UNI_model[0];
+ mat3 model3 = mat3(model0[0].xyz, model0[1].xyz, model0[2].xyz);
+ vec3 worldNorm = model3 * ATTRIB_normal;
+ vec3 V = normalize(-worldPos.xyz);
+
+ vec3 light0Vec = normalize(UNI_light_Posision[0].xyz - worldPos.xyz);
+ vec3 light0R = -reflect(light0Vec, worldNorm);
+ light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light_Diffuse[0];
+ float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
+ light0_Specular = pow(light0Spec, UNI_light_CosinePower[0]) * UNI_light_Specular[0];
+
+ vec3 light1Vec = normalize(UNI_light_Posision[1].xyz - worldPos.xyz);
+ vec3 light1R = reflect(light1Vec, worldNorm);
+ light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light_Diffuse[1];
+ float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
+ light1_Specular = pow(light1Spec, UNI_light_CosinePower[1]) * UNI_light_Specular[1];
+
+ gl_PointSize = 1.0;
+ varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl
new file mode 100644
index 0000000..15696a4
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl
@@ -0,0 +1,8 @@
+
+varying vec3 worldNormal;
+
+void main() {
+ lowp vec4 col = textureCube(UNI_Tex0, worldNormal);
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl
new file mode 100644
index 0000000..70f5cd6
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl
@@ -0,0 +1,10 @@
+varying vec3 worldNormal;
+
+// This is where actual shader code begins
+void main() {
+ vec4 worldPos = UNI_model * ATTRIB_position;
+ gl_Position = UNI_proj * worldPos;
+
+ mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+ worldNormal = model3 * ATTRIB_normal;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl
new file mode 100644
index 0000000..d56e203
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl
@@ -0,0 +1,16 @@
+
+varying lowp float light0_Diffuse;
+varying lowp float light0_Specular;
+varying lowp float light1_Diffuse;
+varying lowp float light1_Specular;
+varying vec2 varTex0;
+
+void main() {
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz);
+ col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz;
+ col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz;
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl
new file mode 100644
index 0000000..f7d01de
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl
@@ -0,0 +1,30 @@
+varying float light0_Diffuse;
+varying float light0_Specular;
+varying float light1_Diffuse;
+varying float light1_Specular;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+ vec4 worldPos = UNI_model * ATTRIB_position;
+ gl_Position = UNI_proj * worldPos;
+
+ mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+ vec3 worldNorm = model3 * ATTRIB_normal;
+ vec3 V = normalize(-worldPos.xyz);
+
+ vec3 light0Vec = normalize(UNI_light0_Posision.xyz - worldPos.xyz);
+ vec3 light0R = -reflect(light0Vec, worldNorm);
+ light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse;
+ float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
+ light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular;
+
+ vec3 light1Vec = normalize(UNI_light1_Posision.xyz - worldPos.xyz);
+ vec3 light1R = reflect(light1Vec, worldNorm);
+ light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse;
+ float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
+ light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular;
+
+ gl_PointSize = 1.0;
+ varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d b/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d
new file mode 100644
index 0000000..0322b01
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java
new file mode 100644
index 0000000..dade3b3
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.miscsamples;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class RsList extends Activity {
+
+ private RsListView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new RsListView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity loses focus
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity loses focus
+ super.onPause();
+ mView.pause();
+ }
+
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java
new file mode 100644
index 0000000..eeb2480
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.miscsamples;
+
+import java.io.Writer;
+import java.util.Vector;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+
+public class RsListRS {
+
+ private final int STATE_LAST_FOCUS = 1;
+
+ private static final String[] DATA_LIST = {
+ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+ "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+ "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+ "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+ "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+ "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil",
+ "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria",
+ "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+ "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+ "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+ "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+ "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+ "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+ "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+ "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+ "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+ "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+ "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+ "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+ "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+ "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+ "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+ "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+ "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+ "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+ "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+ "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+ "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+ "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+ "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+ "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+ "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+ "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+ "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+ "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+ "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+ "Ukraine", "United Arab Emirates", "United Kingdom",
+ "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+ "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+ "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+ };
+
+ public RsListRS() {
+ }
+
+ public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+ initRS();
+ }
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ private Font mItalic;
+
+ ScriptField_ListAllocs_s mListAllocs;
+
+ private ScriptC_rslist mScript;
+
+ int mLastX;
+ int mLastY;
+
+ public void onActionDown(int x, int y) {
+ mScript.set_gDY(0.0f);
+
+ mLastX = x;
+ mLastY = y;
+ }
+
+ public void onActionMove(int x, int y) {
+ int dx = mLastX - x;
+ int dy = mLastY - y;
+
+ if (Math.abs(dy) <= 2) {
+ dy = 0;
+ }
+
+ mScript.set_gDY(dy);
+
+ mLastX = x;
+ mLastY = y;
+ }
+
+ private void initRS() {
+
+ mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist);
+
+ mListAllocs = new ScriptField_ListAllocs_s(mRS, DATA_LIST.length);
+ for (int i = 0; i < DATA_LIST.length; i ++) {
+ ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
+ listElem.text = Allocation.createFromString(mRS, DATA_LIST[i], Allocation.USAGE_SCRIPT);
+ mListAllocs.set(listElem, i, false);
+ }
+
+ mListAllocs.copyAll();
+
+ mScript.bind_gList(mListAllocs);
+
+ mItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8);
+ mScript.set_gItalic(mItalic);
+
+ mRS.bindRootScript(mScript);
+ }
+}
+
+
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java
new file mode 100644
index 0000000..db6e6c5
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.miscsamples;
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.view.MotionEvent;
+
+public class RsListView extends RSSurfaceView {
+
+ public RsListView(Context context) {
+ super(context);
+ ensureRenderScript();
+ }
+
+ private RenderScriptGL mRS;
+ private RsListRS mRender;
+
+ private void ensureRenderScript() {
+ if (mRS == null) {
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ mRS = createRenderScriptGL(sc);
+ mRender = new RsListRS();
+ mRender.init(mRS, getResources());
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ ensureRenderScript();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ mRender = null;
+ if (mRS != null) {
+ mRS = null;
+ destroyRenderScriptGL();
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ boolean ret = false;
+ int act = ev.getAction();
+ if (act == MotionEvent.ACTION_DOWN) {
+ mRender.onActionDown((int)ev.getX(), (int)ev.getY());
+ ret = true;
+ } else if (act == MotionEvent.ACTION_MOVE) {
+ mRender.onActionMove((int)ev.getX(), (int)ev.getY());
+ ret = true;
+ }
+
+ return ret;
+ }
+}
+
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java
new file mode 100644
index 0000000..f4ea76e
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.miscsamples;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class RsRenderStates extends Activity {
+
+ private RsRenderStatesView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new RsRenderStatesView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.pause();
+ }
+
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java
new file mode 100644
index 0000000..0e319fe
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.miscsamples;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.renderscript.*;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.renderscript.ProgramStore.BlendSrcFunc;
+import android.renderscript.ProgramStore.BlendDstFunc;
+import android.renderscript.Sampler.Value;
+import android.util.Log;
+
+
+public class RsRenderStatesRS {
+
+ int mWidth;
+ int mHeight;
+
+ public RsRenderStatesRS() {
+ }
+
+ public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mWidth = mRS.getWidth();
+ mHeight = mRS.getHeight();
+ mRes = res;
+ mOptionsARGB.inScaled = false;
+ mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ mMode = 0;
+ mMaxModes = 0;
+ initRS();
+ }
+
+ public void surfaceChanged() {
+ mWidth = mRS.getWidth();
+ mHeight = mRS.getHeight();
+
+ Matrix4f proj = new Matrix4f();
+ proj.loadOrthoWindow(mWidth, mHeight);
+ mPVA.setProjection(proj);
+ }
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+
+ private Sampler mLinearClamp;
+ private Sampler mLinearWrap;
+ private Sampler mMipLinearWrap;
+ private Sampler mNearestClamp;
+ private Sampler mMipLinearAniso8;
+ private Sampler mMipLinearAniso15;
+
+ private ProgramStore mProgStoreBlendNoneDepth;
+ private ProgramStore mProgStoreBlendNone;
+ private ProgramStore mProgStoreBlendAlpha;
+ private ProgramStore mProgStoreBlendAdd;
+
+ private ProgramFragment mProgFragmentTexture;
+ private ProgramFragment mProgFragmentColor;
+
+ private ProgramVertex mProgVertex;
+ private ProgramVertexFixedFunction.Constants mPVA;
+
+ // Custom shaders
+ private ProgramVertex mProgVertexCustom;
+ private ProgramFragment mProgFragmentCustom;
+ private ProgramFragment mProgFragmentMultitex;
+ private ScriptField_VertexShaderConstants_s mVSConst;
+ private ScriptField_VertexShaderConstants2_s mVSConst2;
+ private ScriptField_FragentShaderConstants_s mFSConst;
+ private ScriptField_FragentShaderConstants2_s mFSConst2;
+
+ private ProgramVertex mProgVertexCustom2;
+ private ProgramFragment mProgFragmentCustom2;
+
+ private ProgramVertex mProgVertexCube;
+ private ProgramFragment mProgFragmentCube;
+
+ private ProgramRaster mCullBack;
+ private ProgramRaster mCullFront;
+ private ProgramRaster mCullNone;
+
+ private Allocation mTexTorus;
+ private Allocation mTexOpaque;
+ private Allocation mTexTransparent;
+ private Allocation mTexChecker;
+ private Allocation mTexCube;
+
+ private Mesh mMbyNMesh;
+ private Mesh mTorus;
+
+ Font mFontSans;
+ Font mFontSerif;
+ Font mFontSerifBold;
+ Font mFontSerifItalic;
+ Font mFontSerifBoldItalic;
+ Font mFontMono;
+ private Allocation mTextAlloc;
+
+ private ScriptC_rsrenderstates mScript;
+
+ private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
+
+ int mMode;
+ int mMaxModes;
+
+ public void onActionDown(int x, int y) {
+ mMode ++;
+ mMode = mMode % mMaxModes;
+ mScript.set_gDisplayMode(mMode);
+ }
+
+ ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
+ ProgramStore.Builder builder = new ProgramStore.Builder(rs);
+ builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+ builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
+ builder.setDitherEnabled(false);
+ builder.setDepthMaskEnabled(false);
+ return builder.create();
+ }
+
+ private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) {
+
+ Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
+ 2, Mesh.TriangleMeshBuilder.TEXTURE_0);
+
+ for (int y = 0; y <= hResolution; y++) {
+ final float normalizedY = (float)y / hResolution;
+ final float yOffset = (normalizedY - 0.5f) * height;
+ for (int x = 0; x <= wResolution; x++) {
+ float normalizedX = (float)x / wResolution;
+ float xOffset = (normalizedX - 0.5f) * width;
+ tmb.setTexture(normalizedX, normalizedY);
+ tmb.addVertex(xOffset, yOffset);
+ }
+ }
+
+ for (int y = 0; y < hResolution; y++) {
+ final int curY = y * (wResolution + 1);
+ final int belowY = (y + 1) * (wResolution + 1);
+ for (int x = 0; x < wResolution; x++) {
+ int curV = curY + x;
+ int belowV = belowY + x;
+ tmb.addTriangle(curV, belowV, curV + 1);
+ tmb.addTriangle(belowV, belowV + 1, curV + 1);
+ }
+ }
+
+ return tmb.create(true);
+ }
+
+ private void initProgramStore() {
+ // Use stock the stock program store object
+ mProgStoreBlendNoneDepth = ProgramStore.BLEND_NONE_DEPTH_TEST(mRS);
+ mProgStoreBlendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(mRS);
+
+ // Create a custom program store
+ ProgramStore.Builder builder = new ProgramStore.Builder(mRS);
+ builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+ builder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
+ ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+ builder.setDitherEnabled(false);
+ builder.setDepthMaskEnabled(false);
+ mProgStoreBlendAlpha = builder.create();
+
+ mProgStoreBlendAdd = BLEND_ADD_DEPTH_NONE(mRS);
+
+ mScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth);
+ mScript.set_gProgStoreBlendNone(mProgStoreBlendNone);
+ mScript.set_gProgStoreBlendAlpha(mProgStoreBlendAlpha);
+ mScript.set_gProgStoreBlendAdd(mProgStoreBlendAdd);
+ }
+
+ private void initProgramFragment() {
+
+ ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
+ texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+ ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+ mProgFragmentTexture = texBuilder.create();
+ mProgFragmentTexture.bindSampler(mLinearClamp, 0);
+
+ ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
+ colBuilder.setVaryingColor(false);
+ mProgFragmentColor = colBuilder.create();
+
+ mScript.set_gProgFragmentColor(mProgFragmentColor);
+ mScript.set_gProgFragmentTexture(mProgFragmentTexture);
+ }
+
+ private void initProgramVertex() {
+ ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
+ mProgVertex = pvb.create();
+
+ mPVA = new ProgramVertexFixedFunction.Constants(mRS);
+ ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA);
+ Matrix4f proj = new Matrix4f();
+ proj.loadOrthoWindow(mWidth, mHeight);
+ mPVA.setProjection(proj);
+
+ mScript.set_gProgVertex(mProgVertex);
+ }
+
+ private void initCustomShaders() {
+ mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1);
+ mVSConst2 = new ScriptField_VertexShaderConstants2_s(mRS, 1);
+ mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1);
+ mFSConst2 = new ScriptField_FragentShaderConstants2_s(mRS, 1);
+
+ mScript.bind_gVSConstants(mVSConst);
+ mScript.bind_gVSConstants2(mVSConst2);
+ mScript.bind_gFSConstants(mFSConst);
+ mScript.bind_gFSConstants2(mFSConst2);
+
+ // Initialize the shader builder
+ ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS);
+ // Specify the resource that contains the shader string
+ pvbCustom.setShader(mRes, R.raw.shaderv);
+ // Use a script field to spcify the input layout
+ pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
+ // Define the constant input layout
+ pvbCustom.addConstant(mVSConst.getAllocation().getType());
+ mProgVertexCustom = pvbCustom.create();
+ // Bind the source of constant data
+ mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0);
+
+ ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS);
+ // Specify the resource that contains the shader string
+ pfbCustom.setShader(mRes, R.raw.shaderf);
+ //Tell the builder how many textures we have
+ pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
+ // Define the constant input layout
+ pfbCustom.addConstant(mFSConst.getAllocation().getType());
+ mProgFragmentCustom = pfbCustom.create();
+ // Bind the source of constant data
+ mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0);
+
+ pvbCustom = new ProgramVertex.Builder(mRS);
+ pvbCustom.setShader(mRes, R.raw.shaderarrayv);
+ pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
+ pvbCustom.addConstant(mVSConst2.getAllocation().getType());
+ mProgVertexCustom2 = pvbCustom.create();
+ mProgVertexCustom2.bindConstants(mVSConst2.getAllocation(), 0);
+
+ pfbCustom = new ProgramFragment.Builder(mRS);
+ pfbCustom.setShader(mRes, R.raw.shaderarrayf);
+ pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
+ pfbCustom.addConstant(mFSConst2.getAllocation().getType());
+ mProgFragmentCustom2 = pfbCustom.create();
+ mProgFragmentCustom2.bindConstants(mFSConst2.getAllocation(), 0);
+
+ // Cubemap test shaders
+ pvbCustom = new ProgramVertex.Builder(mRS);
+ pvbCustom.setShader(mRes, R.raw.shadercubev);
+ pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
+ pvbCustom.addConstant(mVSConst.getAllocation().getType());
+ mProgVertexCube = pvbCustom.create();
+ mProgVertexCube.bindConstants(mVSConst.getAllocation(), 0);
+
+ pfbCustom = new ProgramFragment.Builder(mRS);
+ pfbCustom.setShader(mRes, R.raw.shadercubef);
+ pfbCustom.addTexture(Program.TextureType.TEXTURE_CUBE);
+ mProgFragmentCube = pfbCustom.create();
+
+ pfbCustom = new ProgramFragment.Builder(mRS);
+ pfbCustom.setShader(mRes, R.raw.multitexf);
+ for (int texCount = 0; texCount < 3; texCount ++) {
+ pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
+ }
+ mProgFragmentMultitex = pfbCustom.create();
+
+ mScript.set_gProgVertexCustom(mProgVertexCustom);
+ mScript.set_gProgFragmentCustom(mProgFragmentCustom);
+ mScript.set_gProgVertexCustom2(mProgVertexCustom2);
+ mScript.set_gProgFragmentCustom2(mProgFragmentCustom2);
+ mScript.set_gProgVertexCube(mProgVertexCube);
+ mScript.set_gProgFragmentCube(mProgFragmentCube);
+ mScript.set_gProgFragmentMultitex(mProgFragmentMultitex);
+ }
+
+ private Allocation loadTextureRGB(int id) {
+ return Allocation.createFromBitmapResource(mRS, mRes, id,
+ Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
+ }
+
+ private Allocation loadTextureARGB(int id) {
+ Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB);
+ return Allocation.createFromBitmap(mRS, b,
+ Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
+ }
+
+ private void loadImages() {
+ mTexTorus = loadTextureRGB(R.drawable.torusmap);
+ mTexOpaque = loadTextureRGB(R.drawable.data);
+ mTexTransparent = loadTextureARGB(R.drawable.leaf);
+ mTexChecker = loadTextureRGB(R.drawable.checker);
+ Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test);
+ mTexCube = Allocation.createCubemapFromBitmap(mRS, b);
+
+ mScript.set_gTexTorus(mTexTorus);
+ mScript.set_gTexOpaque(mTexOpaque);
+ mScript.set_gTexTransparent(mTexTransparent);
+ mScript.set_gTexChecker(mTexChecker);
+ mScript.set_gTexCube(mTexCube);
+ }
+
+ private void initFonts() {
+ // Sans font by family name
+ mFontSans = Font.create(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8);
+ mFontSerif = Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8);
+ // Create fonts by family and style
+ mFontSerifBold = Font.create(mRS, mRes, "serif", Font.Style.BOLD, 8);
+ mFontSerifItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8);
+ mFontSerifBoldItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8);
+ mFontMono = Font.create(mRS, mRes, "mono", Font.Style.NORMAL, 8);
+
+ mTextAlloc = Allocation.createFromString(mRS, "String from allocation", Allocation.USAGE_SCRIPT);
+
+ mScript.set_gFontSans(mFontSans);
+ mScript.set_gFontSerif(mFontSerif);
+ mScript.set_gFontSerifBold(mFontSerifBold);
+ mScript.set_gFontSerifItalic(mFontSerifItalic);
+ mScript.set_gFontSerifBoldItalic(mFontSerifBoldItalic);
+ mScript.set_gFontMono(mFontMono);
+ mScript.set_gTextAlloc(mTextAlloc);
+ }
+
+ private void initMesh() {
+ mMbyNMesh = getMbyNMesh(256, 256, 10, 10);
+ mScript.set_gMbyNMesh(mMbyNMesh);
+
+ FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus);
+ FileA3D.IndexEntry entry = model.getIndexEntry(0);
+ if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) {
+ Log.e("rs", "could not load model");
+ } else {
+ mTorus = (Mesh)entry.getObject();
+ mScript.set_gTorusMesh(mTorus);
+ }
+ }
+
+ private void initSamplers() {
+ Sampler.Builder bs = new Sampler.Builder(mRS);
+ bs.setMinification(Sampler.Value.LINEAR);
+ bs.setMagnification(Sampler.Value.LINEAR);
+ bs.setWrapS(Sampler.Value.WRAP);
+ bs.setWrapT(Sampler.Value.WRAP);
+ mLinearWrap = bs.create();
+
+ mLinearClamp = Sampler.CLAMP_LINEAR(mRS);
+ mNearestClamp = Sampler.CLAMP_NEAREST(mRS);
+ mMipLinearWrap = Sampler.WRAP_LINEAR_MIP_LINEAR(mRS);
+
+ bs = new Sampler.Builder(mRS);
+ bs.setMinification(Sampler.Value.LINEAR_MIP_LINEAR);
+ bs.setMagnification(Sampler.Value.LINEAR);
+ bs.setWrapS(Sampler.Value.WRAP);
+ bs.setWrapT(Sampler.Value.WRAP);
+ bs.setAnisotropy(8.0f);
+ mMipLinearAniso8 = bs.create();
+ bs.setAnisotropy(15.0f);
+ mMipLinearAniso15 = bs.create();
+
+ mScript.set_gLinearClamp(mLinearClamp);
+ mScript.set_gLinearWrap(mLinearWrap);
+ mScript.set_gMipLinearWrap(mMipLinearWrap);
+ mScript.set_gMipLinearAniso8(mMipLinearAniso8);
+ mScript.set_gMipLinearAniso15(mMipLinearAniso15);
+ mScript.set_gNearestClamp(mNearestClamp);
+ }
+
+ private void initProgramRaster() {
+ mCullBack = ProgramRaster.CULL_BACK(mRS);
+ mCullFront = ProgramRaster.CULL_FRONT(mRS);
+ mCullNone = ProgramRaster.CULL_NONE(mRS);
+
+ mScript.set_gCullBack(mCullBack);
+ mScript.set_gCullFront(mCullFront);
+ mScript.set_gCullNone(mCullNone);
+ }
+
+ private void initRS() {
+
+ mScript = new ScriptC_rsrenderstates(mRS, mRes, R.raw.rsrenderstates);
+
+ mMaxModes = mScript.get_gMaxModes();
+
+ initSamplers();
+ initProgramStore();
+ initProgramFragment();
+ initProgramVertex();
+ initFonts();
+ loadImages();
+ initMesh();
+ initProgramRaster();
+ initCustomShaders();
+
+ mRS.bindRootScript(mScript);
+ }
+}
+
+
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java
new file mode 100644
index 0000000..a15e38f
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.example.android.rs.miscsamples;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+
+public class RsRenderStatesView extends RSSurfaceView {
+
+ public RsRenderStatesView(Context context) {
+ super(context);
+ ensureRenderScript();
+ }
+
+ private RenderScriptGL mRS;
+ private RsRenderStatesRS mRender;
+
+ private void ensureRenderScript() {
+ if (mRS == null) {
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ sc.setDepth(16, 24);
+ mRS = createRenderScriptGL(sc);
+ mRender = new RsRenderStatesRS();
+ mRender.init(mRS, getResources());
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ ensureRenderScript();
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+ mRender.surfaceChanged();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ mRender = null;
+ if (mRS != null) {
+ mRS = null;
+ destroyRenderScriptGL();
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mRender.onActionDown((int)ev.getX(), (int)ev.getY());
+ return true;
+ }
+
+ return false;
+ }
+}
+
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs
new file mode 100644
index 0000000..d9d450d
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs
@@ -0,0 +1,70 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.example.android.rs.miscsamples)
+
+#include "rs_graphics.rsh"
+
+float gDY;
+
+rs_font gItalic;
+
+typedef struct ListAllocs_s {
+ rs_allocation text;
+} ListAllocs;
+
+ListAllocs *gList;
+
+void init() {
+ gDY = 0.0f;
+}
+
+int textPos = 0;
+
+int root(void) {
+
+ rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ textPos -= (int)gDY*2;
+ gDY *= 0.95;
+
+ rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
+ rsgBindFont(gItalic);
+
+ rs_allocation listAlloc;
+ listAlloc = rsGetAllocation(gList);
+ int allocSize = rsAllocationGetDimX(listAlloc);
+
+ int width = rsgGetWidth();
+ int height = rsgGetHeight();
+
+ int itemHeight = 80;
+ int currentYPos = itemHeight + textPos;
+
+ for (int i = 0; i < allocSize; i ++) {
+ if (currentYPos - itemHeight > height) {
+ break;
+ }
+
+ if (currentYPos > 0) {
+ rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0);
+ rsgDrawText(gList[i].text, 30, currentYPos - 32);
+ }
+ currentYPos += itemHeight;
+ }
+
+ return 10;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs
new file mode 100644
index 0000000..5dabd00
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs
@@ -0,0 +1,680 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.example.android.rs.miscsamples)
+
+#include "rs_graphics.rsh"
+#include "shader_def.rsh"
+
+const int gMaxModes = 11;
+
+rs_program_vertex gProgVertex;
+rs_program_fragment gProgFragmentColor;
+rs_program_fragment gProgFragmentTexture;
+
+rs_program_store gProgStoreBlendNoneDepth;
+rs_program_store gProgStoreBlendNone;
+rs_program_store gProgStoreBlendAlpha;
+rs_program_store gProgStoreBlendAdd;
+
+rs_allocation gTexOpaque;
+rs_allocation gTexTorus;
+rs_allocation gTexTransparent;
+rs_allocation gTexChecker;
+rs_allocation gTexCube;
+
+rs_mesh gMbyNMesh;
+rs_mesh gTorusMesh;
+
+rs_font gFontSans;
+rs_font gFontSerif;
+rs_font gFontSerifBold;
+rs_font gFontSerifItalic;
+rs_font gFontSerifBoldItalic;
+rs_font gFontMono;
+rs_allocation gTextAlloc;
+
+int gDisplayMode;
+
+rs_sampler gLinearClamp;
+rs_sampler gLinearWrap;
+rs_sampler gMipLinearWrap;
+rs_sampler gMipLinearAniso8;
+rs_sampler gMipLinearAniso15;
+rs_sampler gNearestClamp;
+
+rs_program_raster gCullBack;
+rs_program_raster gCullFront;
+rs_program_raster gCullNone;
+
+// Custom vertex shader compunents
+VertexShaderConstants *gVSConstants;
+VertexShaderConstants2 *gVSConstants2;
+FragentShaderConstants *gFSConstants;
+FragentShaderConstants2 *gFSConstants2;
+// Export these out to easily set the inputs to shader
+VertexShaderInputs *gVSInputs;
+// Custom shaders we use for lighting
+rs_program_vertex gProgVertexCustom;
+rs_program_fragment gProgFragmentCustom;
+rs_program_vertex gProgVertexCustom2;
+rs_program_fragment gProgFragmentCustom2;
+rs_program_vertex gProgVertexCube;
+rs_program_fragment gProgFragmentCube;
+rs_program_fragment gProgFragmentMultitex;
+
+float gDt = 0;
+
+void init() {
+}
+
+static void displayFontSamples() {
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ int yPos = 100;
+ rsgBindFont(gFontSans);
+ rsgDrawText("Sans font sample", 30, yPos);
+ yPos += 30;
+ rsgFontColor(0.5f, 0.9f, 0.5f, 1.0f);
+ rsgBindFont(gFontSerif);
+ rsgDrawText("Serif font sample", 30, yPos);
+ yPos += 30;
+ rsgFontColor(0.7f, 0.7f, 0.7f, 1.0f);
+ rsgBindFont(gFontSerifBold);
+ rsgDrawText("Serif Bold font sample", 30, yPos);
+ yPos += 30;
+ rsgFontColor(0.5f, 0.5f, 0.9f, 1.0f);
+ rsgBindFont(gFontSerifItalic);
+ rsgDrawText("Serif Italic font sample", 30, yPos);
+ yPos += 30;
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontSerifBoldItalic);
+ rsgDrawText("Serif Bold Italic font sample", 30, yPos);
+ yPos += 30;
+ rsgBindFont(gFontMono);
+ rsgDrawText("Monospace font sample", 30, yPos);
+ yPos += 50;
+
+ // Now use text metrics to center the text
+ uint width = rsgGetWidth();
+ uint height = rsgGetHeight();
+ int left = 0, right = 0, top = 0, bottom = 0;
+
+ rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
+ rsgBindFont(gFontSerifBoldItalic);
+
+ rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom);
+ int centeredPos = width / 2 - (right - left) / 2;
+ rsgDrawText(gTextAlloc, centeredPos, yPos);
+ yPos += 30;
+
+ const char* text = "Centered Text Sample";
+ rsgMeasureText(text, &left, &right, &top, &bottom);
+ centeredPos = width / 2 - (right - left) / 2;
+ rsgDrawText(text, centeredPos, yPos);
+ yPos += 30;
+
+ rsgBindFont(gFontSans);
+ text = "More Centered Text Samples";
+ rsgMeasureText(text, &left, &right, &top, &bottom);
+ centeredPos = width / 2 - (right - left) / 2;
+ rsgDrawText(text, centeredPos, yPos);
+ yPos += 30;
+
+ // Now draw bottom and top right aligned text
+ text = "Top-right aligned text";
+ rsgMeasureText(text, &left, &right, &top, &bottom);
+ rsgDrawText(text, width - right, top);
+
+ text = "Top-left";
+ rsgMeasureText(text, &left, &right, &top, &bottom);
+ rsgDrawText(text, -left, top);
+
+ text = "Bottom-right aligned text";
+ rsgMeasureText(text, &left, &right, &top, &bottom);
+ rsgDrawText(text, width - right, height + bottom);
+
+}
+
+static void bindProgramVertexOrtho() {
+ // Default vertex sahder
+ rsgBindProgramVertex(gProgVertex);
+ // Setup the projectioni matrix
+ rs_matrix4x4 proj;
+ rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
+}
+
+static void displayShaderSamples() {
+ bindProgramVertexOrtho();
+ rs_matrix4x4 matrix;
+ rsMatrixLoadIdentity(&matrix);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNone);
+ rsgBindProgramFragment(gProgFragmentTexture);
+ rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+
+ float startX = 0, startY = 0;
+ float width = 256, height = 256;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+ startX, startY + height, 0, 0, 1,
+ startX + width, startY + height, 0, 1, 1,
+ startX + width, startY, 0, 1, 0);
+
+ startX = 200; startY = 0;
+ width = 128; height = 128;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+ startX, startY + height, 0, 0, 1,
+ startX + width, startY + height, 0, 1, 1,
+ startX + width, startY, 0, 1, 0);
+
+ rsgBindProgramStore(gProgStoreBlendAlpha);
+ rsgBindTexture(gProgFragmentTexture, 0, gTexTransparent);
+ startX = 0; startY = 200;
+ width = 128; height = 128;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+ startX, startY + height, 0, 0, 1,
+ startX + width, startY + height, 0, 1, 1,
+ startX + width, startY, 0, 1, 0);
+
+ // Fragment program with simple color
+ rsgBindProgramFragment(gProgFragmentColor);
+ rsgProgramFragmentConstantColor(gProgFragmentColor, 0.9, 0.3, 0.3, 1);
+ rsgDrawRect(200, 300, 350, 450, 0);
+ rsgProgramFragmentConstantColor(gProgFragmentColor, 0.3, 0.9, 0.3, 1);
+ rsgDrawRect(50, 400, 400, 600, 0);
+
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontMono);
+ rsgDrawText("Texture shader", 10, 50);
+ rsgDrawText("Alpha-blended texture shader", 10, 280);
+ rsgDrawText("Flat color shader", 100, 450);
+}
+
+static void displayBlendingSamples() {
+ int i;
+
+ bindProgramVertexOrtho();
+ rs_matrix4x4 matrix;
+ rsMatrixLoadIdentity(&matrix);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+
+ rsgBindProgramFragment(gProgFragmentColor);
+
+ rsgBindProgramStore(gProgStoreBlendNone);
+ for (i = 0; i < 3; i ++) {
+ float iPlusOne = (float)(i + 1);
+ rsgProgramFragmentConstantColor(gProgFragmentColor,
+ 0.1f*iPlusOne, 0.2f*iPlusOne, 0.3f*iPlusOne, 1);
+ float yPos = 150 * (float)i;
+ rsgDrawRect(0, yPos, 200, yPos + 200, 0);
+ }
+
+ rsgBindProgramStore(gProgStoreBlendAlpha);
+ for (i = 0; i < 3; i ++) {
+ float iPlusOne = (float)(i + 1);
+ rsgProgramFragmentConstantColor(gProgFragmentColor,
+ 0.2f*iPlusOne, 0.3f*iPlusOne, 0.1f*iPlusOne, 0.5);
+ float yPos = 150 * (float)i;
+ rsgDrawRect(150, yPos, 350, yPos + 200, 0);
+ }
+
+ rsgBindProgramStore(gProgStoreBlendAdd);
+ for (i = 0; i < 3; i ++) {
+ float iPlusOne = (float)(i + 1);
+ rsgProgramFragmentConstantColor(gProgFragmentColor,
+ 0.3f*iPlusOne, 0.1f*iPlusOne, 0.2f*iPlusOne, 0.5);
+ float yPos = 150 * (float)i;
+ rsgDrawRect(300, yPos, 500, yPos + 200, 0);
+ }
+
+
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontMono);
+ rsgDrawText("No Blending", 10, 50);
+ rsgDrawText("Alpha Blending", 160, 150);
+ rsgDrawText("Additive Blending", 320, 250);
+
+}
+
+static void displayMeshSamples() {
+
+ bindProgramVertexOrtho();
+ rs_matrix4x4 matrix;
+ rsMatrixLoadTranslate(&matrix, 128, 128, 0);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNone);
+ rsgBindProgramFragment(gProgFragmentTexture);
+ rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+
+ rsgDrawMesh(gMbyNMesh);
+
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontMono);
+ rsgDrawText("User gen 10 by 10 grid mesh", 10, 250);
+}
+
+static void displayTextureSamplers() {
+
+ bindProgramVertexOrtho();
+ rs_matrix4x4 matrix;
+ rsMatrixLoadIdentity(&matrix);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNone);
+ rsgBindProgramFragment(gProgFragmentTexture);
+ rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+
+ // Linear clamp
+ rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+ float startX = 0, startY = 0;
+ float width = 300, height = 300;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+ startX, startY + height, 0, 0, 1.1,
+ startX + width, startY + height, 0, 1.1, 1.1,
+ startX + width, startY, 0, 1.1, 0);
+
+ // Linear Wrap
+ rsgBindSampler(gProgFragmentTexture, 0, gLinearWrap);
+ startX = 0; startY = 300;
+ width = 300; height = 300;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+ startX, startY + height, 0, 0, 1.1,
+ startX + width, startY + height, 0, 1.1, 1.1,
+ startX + width, startY, 0, 1.1, 0);
+
+ // Nearest
+ rsgBindSampler(gProgFragmentTexture, 0, gNearestClamp);
+ startX = 300; startY = 0;
+ width = 300; height = 300;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+ startX, startY + height, 0, 0, 1.1,
+ startX + width, startY + height, 0, 1.1, 1.1,
+ startX + width, startY, 0, 1.1, 0);
+
+ rsgBindSampler(gProgFragmentTexture, 0, gMipLinearWrap);
+ startX = 300; startY = 300;
+ width = 300; height = 300;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+ startX, startY + height, 0, 0, 1.5,
+ startX + width, startY + height, 0, 1.5, 1.5,
+ startX + width, startY, 0, 1.5, 0);
+
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontMono);
+ rsgDrawText("Filtering: linear clamp", 10, 290);
+ rsgDrawText("Filtering: linear wrap", 10, 590);
+ rsgDrawText("Filtering: nearest clamp", 310, 290);
+ rsgDrawText("Filtering: miplinear wrap", 310, 590);
+}
+
+static float gTorusRotation = 0;
+
+static void displayCullingSamples() {
+ rsgBindProgramVertex(gProgVertex);
+ // Setup the projectioni matrix with 60 degree field of view
+ rs_matrix4x4 proj;
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNoneDepth);
+ rsgBindProgramFragment(gProgFragmentTexture);
+ rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentTexture, 0, gTexTorus);
+
+ // Aplly a rotation to our mesh
+ gTorusRotation += 50.0f * gDt;
+ if (gTorusRotation > 360.0f) {
+ gTorusRotation -= 360.0f;
+ }
+
+ rs_matrix4x4 matrix;
+ // Position our model on the screen
+ rsMatrixLoadTranslate(&matrix, -2.0f, 0.0f, -10.0f);
+ rsMatrixRotate(&matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+ // Use front face culling
+ rsgBindProgramRaster(gCullFront);
+ rsgDrawMesh(gTorusMesh);
+
+ rsMatrixLoadTranslate(&matrix, 2.0f, 0.0f, -10.0f);
+ rsMatrixRotate(&matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+ // Use back face culling
+ rsgBindProgramRaster(gCullBack);
+ rsgDrawMesh(gTorusMesh);
+
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontMono);
+ rsgDrawText("Displaying mesh front/back face culling", 10, rsgGetHeight() - 10);
+}
+
+static float gLight0Rotation = 0;
+static float gLight1Rotation = 0;
+
+static void setupCustomShaderLights() {
+ float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f};
+ float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f};
+ float4 light0DiffCol = {0.9f, 0.7f, 0.7f, 1.0f};
+ float4 light0SpecCol = {0.9f, 0.6f, 0.6f, 1.0f};
+ float4 light1DiffCol = {0.5f, 0.5f, 0.9f, 1.0f};
+ float4 light1SpecCol = {0.5f, 0.5f, 0.9f, 1.0f};
+
+ gLight0Rotation += 50.0f * gDt;
+ if (gLight0Rotation > 360.0f) {
+ gLight0Rotation -= 360.0f;
+ }
+ gLight1Rotation -= 50.0f * gDt;
+ if (gLight1Rotation > 360.0f) {
+ gLight1Rotation -= 360.0f;
+ }
+
+ rs_matrix4x4 l0Mat;
+ rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f);
+ light0Pos = rsMatrixMultiply(&l0Mat, light0Pos);
+ rs_matrix4x4 l1Mat;
+ rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f);
+ light1Pos = rsMatrixMultiply(&l1Mat, light1Pos);
+
+ // Set light 0 properties
+ gVSConstants->light0_Posision = light0Pos;
+ gVSConstants->light0_Diffuse = 1.0f;
+ gVSConstants->light0_Specular = 0.5f;
+ gVSConstants->light0_CosinePower = 10.0f;
+ // Set light 1 properties
+ gVSConstants->light1_Posision = light1Pos;
+ gVSConstants->light1_Diffuse = 1.0f;
+ gVSConstants->light1_Specular = 0.7f;
+ gVSConstants->light1_CosinePower = 25.0f;
+ rsgAllocationSyncAll(rsGetAllocation(gVSConstants));
+
+ gVSConstants2->light_Posision[0] = light0Pos;
+ gVSConstants2->light_Diffuse[0] = 1.0f;
+ gVSConstants2->light_Specular[0] = 0.5f;
+ gVSConstants2->light_CosinePower[0] = 10.0f;
+ gVSConstants2->light_Posision[1] = light1Pos;
+ gVSConstants2->light_Diffuse[1] = 1.0f;
+ gVSConstants2->light_Specular[1] = 0.7f;
+ gVSConstants2->light_CosinePower[1] = 25.0f;
+ rsgAllocationSyncAll(rsGetAllocation(gVSConstants2));
+
+ // Update fragmetn shader constants
+ // Set light 0 colors
+ gFSConstants->light0_DiffuseColor = light0DiffCol;
+ gFSConstants->light0_SpecularColor = light0SpecCol;
+ // Set light 1 colors
+ gFSConstants->light1_DiffuseColor = light1DiffCol;
+ gFSConstants->light1_SpecularColor = light1SpecCol;
+ rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
+
+ gFSConstants2->light_DiffuseColor[0] = light0DiffCol;
+ gFSConstants2->light_SpecularColor[0] = light0SpecCol;
+ // Set light 1 colors
+ gFSConstants2->light_DiffuseColor[1] = light1DiffCol;
+ gFSConstants2->light_SpecularColor[1] = light1SpecCol;
+ rsgAllocationSyncAll(rsGetAllocation(gFSConstants2));
+}
+
+static void displayCustomShaderSamples() {
+
+ // Update vertex shader constants
+ // Load model matrix
+ // Aplly a rotation to our mesh
+ gTorusRotation += 50.0f * gDt;
+ if (gTorusRotation > 360.0f) {
+ gTorusRotation -= 360.0f;
+ }
+
+ // Position our model on the screen
+ rsMatrixLoadTranslate(&gVSConstants->model, 0.0f, 0.0f, -10.0f);
+ rsMatrixRotate(&gVSConstants->model, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ rsMatrixRotate(&gVSConstants->model, gTorusRotation, 0.0f, 0.0f, 1.0f);
+ // Setup the projectioni matrix
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
+ setupCustomShaderLights();
+
+ rsgBindProgramVertex(gProgVertexCustom);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNoneDepth);
+ rsgBindProgramFragment(gProgFragmentCustom);
+ rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentCustom, 0, gTexTorus);
+
+ // Use back face culling
+ rsgBindProgramRaster(gCullBack);
+ rsgDrawMesh(gTorusMesh);
+
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontMono);
+ rsgDrawText("Custom shader sample", 10, rsgGetHeight() - 10);
+}
+
+static void displayCustomShaderSamples2() {
+
+ // Update vertex shader constants
+ // Load model matrix
+ // Aplly a rotation to our mesh
+ gTorusRotation += 50.0f * gDt;
+ if (gTorusRotation > 360.0f) {
+ gTorusRotation -= 360.0f;
+ }
+
+ // Position our model on the screen
+ rsMatrixLoadTranslate(&gVSConstants2->model[1], 0.0f, 0.0f, -10.0f);
+ rsMatrixLoadIdentity(&gVSConstants2->model[0]);
+ rsMatrixRotate(&gVSConstants2->model[0], gTorusRotation, 1.0f, 0.0f, 0.0f);
+ rsMatrixRotate(&gVSConstants2->model[0], gTorusRotation, 0.0f, 0.0f, 1.0f);
+ // Setup the projectioni matrix
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsMatrixLoadPerspective(&gVSConstants2->proj, 30.0f, aspect, 0.1f, 100.0f);
+ setupCustomShaderLights();
+
+ rsgBindProgramVertex(gProgVertexCustom2);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNoneDepth);
+ rsgBindProgramFragment(gProgFragmentCustom2);
+ rsgBindSampler(gProgFragmentCustom2, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentCustom2, 0, gTexTorus);
+
+ // Use back face culling
+ rsgBindProgramRaster(gCullBack);
+ rsgDrawMesh(gTorusMesh);
+
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontMono);
+ rsgDrawText("Custom shader sample with array uniforms", 10, rsgGetHeight() - 10);
+}
+
+static void displayCubemapShaderSample() {
+ // Update vertex shader constants
+ // Load model matrix
+ // Aplly a rotation to our mesh
+ gTorusRotation += 50.0f * gDt;
+ if (gTorusRotation > 360.0f) {
+ gTorusRotation -= 360.0f;
+ }
+
+ // Position our model on the screen
+ // Position our model on the screen
+ rsMatrixLoadTranslate(&gVSConstants->model, 0.0f, 0.0f, -10.0f);
+ rsMatrixRotate(&gVSConstants->model, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ rsMatrixRotate(&gVSConstants->model, gTorusRotation, 0.0f, 0.0f, 1.0f);
+ // Setup the projectioni matrix
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
+ rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
+
+ rsgBindProgramVertex(gProgVertexCube);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNoneDepth);
+ rsgBindProgramFragment(gProgFragmentCube);
+ rsgBindSampler(gProgFragmentCube, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentCube, 0, gTexCube);
+
+ // Use back face culling
+ rsgBindProgramRaster(gCullBack);
+ rsgDrawMesh(gTorusMesh);
+
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontMono);
+ rsgDrawText("Cubemap shader sample", 10, rsgGetHeight() - 10);
+}
+
+static void displayMultitextureSample() {
+ bindProgramVertexOrtho();
+ rs_matrix4x4 matrix;
+ rsMatrixLoadIdentity(&matrix);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNone);
+ rsgBindProgramFragment(gProgFragmentMultitex);
+ rsgBindSampler(gProgFragmentMultitex, 0, gLinearClamp);
+ rsgBindSampler(gProgFragmentMultitex, 1, gLinearWrap);
+ rsgBindSampler(gProgFragmentMultitex, 2, gLinearClamp);
+ rsgBindTexture(gProgFragmentMultitex, 0, gTexChecker);
+ rsgBindTexture(gProgFragmentMultitex, 1, gTexTorus);
+ rsgBindTexture(gProgFragmentMultitex, 2, gTexTransparent);
+
+ float startX = 0, startY = 0;
+ float width = 256, height = 256;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+ startX, startY + height, 0, 0, 1,
+ startX + width, startY + height, 0, 1, 1,
+ startX + width, startY, 0, 1, 0);
+
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontMono);
+ rsgDrawText("Custom shader with multitexturing", 10, 280);
+}
+
+static float gAnisoTime = 0.0f;
+static uint anisoMode = 0;
+static void displayAnisoSample() {
+
+ gAnisoTime += gDt;
+
+ rsgBindProgramVertex(gProgVertex);
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rs_matrix4x4 proj;
+ rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
+
+ rs_matrix4x4 matrix;
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNone);
+ rsgBindProgramFragment(gProgFragmentTexture);
+ rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, -10.0f);
+ rsMatrixRotate(&matrix, -80, 1.0f, 0.0f, 0.0f);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+
+ rsgBindProgramRaster(gCullNone);
+
+ rsgBindTexture(gProgFragmentTexture, 0, gTexChecker);
+
+ if (gAnisoTime >= 5.0f) {
+ gAnisoTime = 0.0f;
+ anisoMode ++;
+ anisoMode = anisoMode % 3;
+ }
+
+ if (anisoMode == 0) {
+ rsgBindSampler(gProgFragmentTexture, 0, gMipLinearAniso8);
+ } else if (anisoMode == 1) {
+ rsgBindSampler(gProgFragmentTexture, 0, gMipLinearAniso15);
+ } else {
+ rsgBindSampler(gProgFragmentTexture, 0, gMipLinearWrap);
+ }
+
+ float startX = -15;
+ float startY = -15;
+ float width = 30;
+ float height = 30;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+ startX, startY + height, 0, 0, 10,
+ startX + width, startY + height, 0, 10, 10,
+ startX + width, startY, 0, 10, 0);
+
+ rsgBindProgramRaster(gCullBack);
+
+ rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindFont(gFontMono);
+ if (anisoMode == 0) {
+ rsgDrawText("Anisotropic filtering 8", 10, 40);
+ } else if (anisoMode == 1) {
+ rsgDrawText("Anisotropic filtering 15", 10, 40);
+ } else {
+ rsgDrawText("Miplinear filtering", 10, 40);
+ }
+}
+
+int root(void) {
+
+ gDt = rsGetDt();
+
+ rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f);
+ rsgClearDepth(1.0f);
+
+ switch (gDisplayMode) {
+ case 0:
+ displayFontSamples();
+ break;
+ case 1:
+ displayShaderSamples();
+ break;
+ case 2:
+ displayBlendingSamples();
+ break;
+ case 3:
+ displayMeshSamples();
+ break;
+ case 4:
+ displayTextureSamplers();
+ break;
+ case 5:
+ displayCullingSamples();
+ break;
+ case 6:
+ displayCustomShaderSamples();
+ break;
+ case 7:
+ displayMultitextureSample();
+ break;
+ case 8:
+ displayAnisoSample();
+ break;
+ case 9:
+ displayCustomShaderSamples2();
+ break;
+ case 10:
+ displayCubemapShaderSample();
+ break;
+ }
+
+ return 10;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh
new file mode 100644
index 0000000..08cf361
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh
@@ -0,0 +1,83 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.example.android.rs.miscsamples)
+
+typedef struct VertexShaderConstants_s {
+ rs_matrix4x4 model;
+ rs_matrix4x4 proj;
+ float4 light0_Posision;
+ float light0_Diffuse;
+ float light0_Specular;
+ float light0_CosinePower;
+
+ float4 light1_Posision;
+ float light1_Diffuse;
+ float light1_Specular;
+ float light1_CosinePower;
+} VertexShaderConstants;
+
+typedef struct VertexShaderConstants2_s {
+ rs_matrix4x4 model[2];
+ rs_matrix4x4 proj;
+ float4 light_Posision[2];
+ float light_Diffuse[2];
+ float light_Specular[2];
+ float light_CosinePower[2];
+} VertexShaderConstants2;
+
+typedef struct VertexShaderConstants3_s {
+ rs_matrix4x4 model;
+ rs_matrix4x4 proj;
+ float time;
+} VertexShaderConstants3;
+
+
+typedef struct FragentShaderConstants_s {
+ float4 light0_DiffuseColor;
+ float4 light0_SpecularColor;
+
+ float4 light1_DiffuseColor;
+ float4 light1_SpecularColor;
+} FragentShaderConstants;
+
+typedef struct FragentShaderConstants2_s {
+ float4 light_DiffuseColor[2];
+ float4 light_SpecularColor[2];
+} FragentShaderConstants2;
+
+typedef struct FragentShaderConstants3_s {
+ float4 light0_DiffuseColor;
+ float4 light0_SpecularColor;
+ float4 light0_Posision;
+ float light0_Diffuse;
+ float light0_Specular;
+ float light0_CosinePower;
+
+ float4 light1_DiffuseColor;
+ float4 light1_SpecularColor;
+ float4 light1_Posision;
+ float light1_Diffuse;
+ float light1_Specular;
+ float light1_CosinePower;
+} FragentShaderConstants3;
+
+typedef struct VertexShaderInputs_s {
+ float4 position;
+ float3 normal;
+ float2 texture0;
+} VertexShaderInputs;
+