Merge "GenerationCache::get would return a random value instead of NULL Bug #5401917"
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index df1d0bf..c4c3b8a 100755
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -23,6 +23,7 @@
import android.view.IWindowManager;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
+import android.view.MotionEvent;
/**
* Command that sends key events to the device, either by their keycode, or by
@@ -30,6 +31,9 @@
*/
public class Input {
+ private static final String TAG = "Input";
+
+ private IWindowManager mWindowManager;
/**
* Command-line entry point.
@@ -40,6 +44,13 @@
(new Input()).run(args);
}
+ private IWindowManager getWindowManager() {
+ if (mWindowManager == null) {
+ mWindowManager = (IWindowManager.Stub.asInterface(ServiceManager.getService("window")));
+ }
+ return mWindowManager;
+ }
+
private void run(String[] args) {
if (args.length < 1) {
showUsage();
@@ -48,19 +59,37 @@
String command = args[0];
- if (command.equals("text")) {
- sendText(args[1]);
- } else if (command.equals("keyevent")) {
- sendKeyEvent(args[1]);
- } else if (command.equals("motionevent")) {
- System.err.println("Error: motionevent not yet supported.");
- return;
+ try {
+ if (command.equals("text")) {
+ if (args.length == 2) {
+ sendText(args[1]);
+ return;
+ }
+ } else if (command.equals("keyevent")) {
+ if (args.length == 2) {
+ sendKeyEvent(Integer.parseInt(args[1]));
+ return;
+ }
+ } else if (command.equals("tap")) {
+ if (args.length == 3) {
+ sendTap(Float.parseFloat(args[1]), Float.parseFloat(args[2]));
+ return;
+ }
+ } else if (command.equals("swipe")) {
+ if (args.length == 5) {
+ sendSwipe(Float.parseFloat(args[1]), Float.parseFloat(args[2]),
+ Float.parseFloat(args[3]), Float.parseFloat(args[4]));
+ return;
+ }
+ } else {
+ System.err.println("Error: Unknown command: " + command);
+ showUsage();
+ return;
+ }
+ } catch (NumberFormatException ex) {
}
- else {
- System.err.println("Error: Unknown command: " + command);
- showUsage();
- return;
- }
+ System.err.println("Error: Invalid arguments for command: " + command);
+ showUsage();
}
/**
@@ -69,7 +98,6 @@
*
* @param text is a string of characters you want to input to the device.
*/
-
private void sendText(String text) {
StringBuffer buff = new StringBuffer(text);
@@ -90,55 +118,66 @@
char[] chars = buff.toString().toCharArray();
- KeyCharacterMap mKeyCharacterMap = KeyCharacterMap.
- load(KeyCharacterMap.VIRTUAL_KEYBOARD);
-
- KeyEvent[] events = mKeyCharacterMap.getEvents(chars);
-
+ KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ KeyEvent[] events = kcm.getEvents(chars);
for(int i = 0; i < events.length; i++) {
- KeyEvent event = events[i];
- Log.i("SendKeyEvent", Integer.toString(event.getKeyCode()));
- try {
- (IWindowManager.Stub
- .asInterface(ServiceManager.getService("window")))
- .injectKeyEvent(event, true);
- } catch (RemoteException e) {
- Log.i("Input", "DeadOjbectException");
- }
+ injectKeyEvent(events[i]);
}
}
- /**
- * Send a single key event.
- *
- * @param event is a string representing the keycode of the key event you
- * want to execute.
- */
- private void sendKeyEvent(String event) {
- int eventCode = Integer.parseInt(event);
+ private void sendKeyEvent(int keyCode) {
long now = SystemClock.uptimeMillis();
- Log.i("SendKeyEvent", event);
+ injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0));
+ injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0));
+ }
+
+ private void sendTap(float x, float y) {
+ long now = SystemClock.uptimeMillis();
+ injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x, y, 0));
+ injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x, y, 0));
+ }
+
+ private void sendSwipe(float x1, float y1, float x2, float y2) {
+ final int NUM_STEPS = 11;
+ long now = SystemClock.uptimeMillis();
+ injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x1, y1, 0));
+ for (int i = 1; i < NUM_STEPS; i++) {
+ float alpha = (float)i / NUM_STEPS;
+ injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE,
+ lerp(x1, x2, alpha), lerp(y1, y2, alpha), 0));
+ }
+ injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x2, y2, 0));
+ }
+
+ private void injectKeyEvent(KeyEvent event) {
try {
- KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, eventCode, 0);
- KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, eventCode, 0);
- (IWindowManager.Stub
- .asInterface(ServiceManager.getService("window")))
- .injectKeyEvent(down, true);
- (IWindowManager.Stub
- .asInterface(ServiceManager.getService("window")))
- .injectKeyEvent(up, true);
- } catch (RemoteException e) {
- Log.i("Input", "DeadOjbectException");
+ Log.i(TAG, "InjectKeyEvent: " + event);
+ getWindowManager().injectKeyEvent(event, true);
+ } catch (RemoteException ex) {
+ Log.i(TAG, "RemoteException", ex);
}
}
- private void sendMotionEvent(long downTime, int action, float x, float y,
- float pressure, float size) {
+ private void injectPointerEvent(MotionEvent event) {
+ try {
+ Log.i("Input", "InjectPointerEvent: " + event);
+ getWindowManager().injectPointerEvent(event, true);
+ } catch (RemoteException ex) {
+ Log.i(TAG, "RemoteException", ex);
+ } finally {
+ event.recycle();
+ }
+ }
+
+ private static final float lerp(float a, float b, float alpha) {
+ return (b - a) * alpha + a;
}
private void showUsage() {
System.err.println("usage: input [text|keyevent]");
System.err.println(" input text <string>");
- System.err.println(" input keyevent <event_code>");
+ System.err.println(" input keyevent <key code>");
+ System.err.println(" input tap <x> <y>");
+ System.err.println(" input swipe <x1> <y1> <x2> <y2>");
}
}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 5b8addf..dd9f337 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -56,6 +56,11 @@
| DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER
| DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK;
+ public static final int NAVIGATION_HINT_BACK_NOP = 1 << 0;
+ public static final int NAVIGATION_HINT_HOME_NOP = 1 << 1;
+ public static final int NAVIGATION_HINT_RECENT_NOP = 1 << 2;
+ public static final int NAVIGATION_HINT_BACK_ALT = 1 << 3;
+
private Context mContext;
private IStatusBarService mService;
private IBinder mToken = new Binder();
diff --git a/core/java/android/content/ContentUris.java b/core/java/android/content/ContentUris.java
index aa7603470b..dbe8a7c 100644
--- a/core/java/android/content/ContentUris.java
+++ b/core/java/android/content/ContentUris.java
@@ -19,9 +19,54 @@
import android.net.Uri;
/**
- * Utility methods useful for working with content {@link android.net.Uri}s,
- * those with a "content" scheme.
- */
+* Utility methods useful for working with {@link android.net.Uri} objects
+* that use the "content" (content://) scheme.
+*
+*<p>
+* Content URIs have the syntax
+*</p>
+*<p>
+* <code>content://<em>authority</em>/<em>path</em>/<em>id</em></code>
+*</p>
+*<dl>
+* <dt>
+* <code>content:</code>
+* </dt>
+* <dd>
+* The scheme portion of the URI. This is always set to {@link
+* android.content.ContentResolver#SCHEME_CONTENT ContentResolver.SCHEME_CONTENT} (value
+* <code>content://</code>).
+* </dd>
+* <dt>
+* <em>authority</em>
+* </dt>
+* <dd>
+* A string that identifies the entire content provider. All the content URIs for the provider
+* start with this string. To guarantee a unique authority, providers should consider
+* using an authority that is the same as the provider class' package identifier.
+* </dd>
+* <dt>
+* <em>path</em>
+* </dt>
+* <dd>
+* Zero or more segments, separated by a forward slash (<code>/</code>), that identify
+* some subset of the provider's data. Most providers use the path part to identify
+* individual tables. Individual segments in the path are often called
+* "directories" although they do not refer to file directories. The right-most
+* segment in a path is often called a "twig"
+* </dd>
+* <dt>
+* <em>id</em>
+* </dt>
+* <dd>
+* A unique numeric identifier for a single row in the subset of data identified by the
+* preceding path part. Most providers recognize content URIs that contain an id part
+* and give them special handling. A table that contains a column named <code>_ID</code>
+* often expects the id part to be a particular value for that column.
+* </dd>
+*</dl>
+*
+*/
public class ContentUris {
/**
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index e289fc1..d39e741 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -250,4 +250,32 @@
}
return result;
}
+
+ /**
+ * Trim leading zeros from IPv4 address strings
+ * Our base libraries will interpret that as octel..
+ * Must leave non v4 addresses and host names alone.
+ * For example, 192.168.000.010 -> 192.168.0.10
+ * TODO - fix base libraries and remove this function
+ * @param addr a string representing an ip addr
+ * @return a string propertly trimmed
+ */
+ public static String trimV4AddrZeros(String addr) {
+ if (addr == null) return null;
+ String[] octets = addr.split("\\.");
+ if (octets.length != 4) return addr;
+ StringBuilder builder = new StringBuilder(16);
+ String result = null;
+ for (int i = 0; i < 4; i++) {
+ try {
+ if (octets[i].length() > 3) return addr;
+ builder.append(Integer.parseInt(octets[i]));
+ } catch (NumberFormatException e) {
+ return addr;
+ }
+ if (i < 3) builder.append('.');
+ }
+ result = builder.toString();
+ return result;
+ }
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 7d034940..88fea91 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -311,7 +311,7 @@
public static final int ICE_CREAM_SANDWICH = 14;
/**
- * Android 4.1.
+ * Android 4.0.3.
*/
public static final int ICE_CREAM_SANDWICH_MR1 = 15;
}
diff --git a/core/java/android/os/storage/package.html b/core/java/android/os/storage/package.html
new file mode 100644
index 0000000..a5f1e1c
--- /dev/null
+++ b/core/java/android/os/storage/package.html
@@ -0,0 +1,8 @@
+<HTML>
+<BODY>
+<p>
+Contains classes for the system storage service, which manages binary asset filesystems
+known as Opaque Binary Blobs (OBBs).
+</p>
+</BODY>
+</HTML>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7b0e0ab..c44f23b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2779,10 +2779,10 @@
public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
/**
- * If injection of accessibility enhancing JavaScript scripts
+ * If injection of accessibility enhancing JavaScript screen-reader
* is enabled.
* <p>
- * Note: Accessibility injecting scripts are served by the
+ * Note: The JavaScript based screen-reader is served by the
* Google infrastructure and enable users with disabilities to
* efficiantly navigate in and explore web content.
* </p>
@@ -2795,6 +2795,22 @@
"accessibility_script_injection";
/**
+ * The URL for the injected JavaScript based screen-reader used
+ * for providing accessiblity of content in WebView.
+ * <p>
+ * Note: The JavaScript based screen-reader is served by the
+ * Google infrastructure and enable users with disabilities to
+ * efficiently navigate in and explore web content.
+ * </p>
+ * <p>
+ * This property represents a string value.
+ * </p>
+ * @hide
+ */
+ public static final String ACCESSIBILITY_SCREEN_READER_URL =
+ "accessibility_script_injection_url";
+
+ /**
* Key bindings for navigation in built-in accessibility support for web content.
* <p>
* Note: These key bindings are for the built-in accessibility navigation for
@@ -3132,6 +3148,14 @@
"wifi_watchdog_blacklist_followup_interval_ms";
/**
+ * Setting to turn off poor network avoidance on Wi-Fi. Feature is disabled by default and
+ * the setting needs to be set to 1 to enable it.
+ * @hide
+ */
+ public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED =
+ "wifi_watchdog_poor_network_test_enabled";
+
+ /**
* Setting to turn off walled garden test on Wi-Fi. Feature is enabled by default and
* the setting needs to be set to 0 to disable it.
* @hide
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 0fdd105..63de128 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -66,9 +66,11 @@
// System property to enable/disable the use of the vsync / animation timer
// for drawing rather than drawing immediately.
- // Enabled by default.
+ // Temporarily disabled by default because postponing performTraversals() violates
+ // assumptions about traversals happening in-order relative to other posted messages.
+ // Bug: 5721047
private static final boolean USE_ANIMATION_TIMER_FOR_DRAW = SystemProperties.getBoolean(
- "debug.choreographer.animdraw", true);
+ "debug.choreographer.animdraw", false);
private static final int MSG_DO_ANIMATION = 0;
private static final int MSG_DO_DRAW = 1;
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index aa0bfd2..43a451d 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -154,6 +154,7 @@
static native void nSetTextureLayerTransform(int layerId, int matrix);
static native void nDestroyLayer(int layerId);
static native void nDestroyLayerDeferred(int layerId);
+ static native void nFlushLayer(int layerId);
static native boolean nCopyLayer(int layerId, int bitmap);
///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index fd3b9e5..4f25792 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -60,6 +60,13 @@
}
mLayer = 0;
}
+
+ @Override
+ void flush() {
+ if (mLayer != 0) {
+ GLES20Canvas.nFlushLayer(mLayer);
+ }
+ }
static class Finalizer {
private int mLayerId;
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 28389ab..d5666f3 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -116,6 +116,11 @@
abstract void destroy();
/**
+ * Flush the render queue associated with this layer.
+ */
+ abstract void flush();
+
+ /**
* This must be invoked before drawing onto this layer.
* @param currentCanvas
*/
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 304a9a1..5c93a42 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10207,6 +10207,13 @@
break;
}
}
+
+ // Make sure the HardwareRenderer.validate() was invoked before calling this method
+ void flushLayer() {
+ if (mLayerType == LAYER_TYPE_HARDWARE && mHardwareLayer != null) {
+ mHardwareLayer.flush();
+ }
+ }
/**
* <p>Returns a hardware layer that can be used to draw this view again
@@ -10219,6 +10226,8 @@
!mAttachInfo.mHardwareRenderer.isEnabled()) {
return null;
}
+
+ if (!mAttachInfo.mHardwareRenderer.validate()) return null;
final int width = mRight - mLeft;
final int height = mBottom - mTop;
@@ -10293,12 +10302,15 @@
*/
boolean destroyLayer() {
if (mHardwareLayer != null) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
+ AttachInfo info = mAttachInfo;
+ if (info != null && info.mHardwareRenderer != null &&
+ info.mHardwareRenderer.isEnabled() && info.mHardwareRenderer.validate()) {
+ mHardwareLayer.destroy();
+ mHardwareLayer = null;
- invalidate(true);
- invalidateParentCaches();
-
+ invalidate(true);
+ invalidateParentCaches();
+ }
return true;
}
return false;
@@ -12208,13 +12220,16 @@
* @param location an array of two integers in which to hold the coordinates
*/
public void getLocationInWindow(int[] location) {
- // When the view is not attached to a window, this method does not make sense
- if (mAttachInfo == null) return;
-
if (location == null || location.length < 2) {
throw new IllegalArgumentException("location must be an array of two integers");
}
+ if (mAttachInfo == null) {
+ // When the view is not attached to a window, this method does not make sense
+ location[0] = location[1] = 0;
+ return;
+ }
+
float[] position = mAttachInfo.mTmpTransformLocation;
position[0] = position[1] = 0.0f;
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index d824e36..b455ad5 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -139,9 +139,17 @@
private static final int EDGE_SLOP = 12;
/**
- * Distance a touch can wander before we think the user is scrolling in dips
+ * Distance a touch can wander before we think the user is scrolling in dips.
+ * Note that this value defined here is only used as a fallback by legacy/misbehaving
+ * applications that do not provide a Context for determining density/configuration-dependent
+ * values.
+ *
+ * To alter this value, see the configuration resource config_viewConfigurationTouchSlop
+ * in frameworks/base/core/res/res/values/config.xml or the appropriate device resource overlay.
+ * It may be appropriate to tweak this on a device-specific basis in an overlay based on
+ * the characteristics of the touch panel and firmware.
*/
- private static final int TOUCH_SLOP = 16;
+ private static final int TOUCH_SLOP = 8;
/**
* Distance the first touch can wander before we stop considering this event a double tap
@@ -152,6 +160,14 @@
/**
* Distance a touch can wander before we think the user is attempting a paged scroll
* (in dips)
+ *
+ * Note that this value defined here is only used as a fallback by legacy/misbehaving
+ * applications that do not provide a Context for determining density/configuration-dependent
+ * values.
+ *
+ * See the note above on {@link #TOUCH_SLOP} regarding the dimen resource
+ * config_viewConfigurationTouchSlop. ViewConfiguration will report a paging touch slop of
+ * config_viewConfigurationTouchSlop * 2 when provided with a Context.
*/
private static final int PAGING_TOUCH_SLOP = TOUCH_SLOP * 2;
@@ -285,9 +301,6 @@
mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
- mTouchSlop = (int) (sizeAndDensity * TOUCH_SLOP + 0.5f);
- mDoubleTapTouchSlop = (int) (sizeAndDensity * DOUBLE_TAP_TOUCH_SLOP + 0.5f);
- mPagingTouchSlop = (int) (sizeAndDensity * PAGING_TOUCH_SLOP + 0.5f);
mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
mScaledTouchExplorationTapSlop = (int) (density * TOUCH_EXPLORATION_TAP_SLOP + 0.5f);
mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
@@ -310,6 +323,11 @@
mFadingMarqueeEnabled = res.getBoolean(
com.android.internal.R.bool.config_ui_enableFadingMarquee);
+ mTouchSlop = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.config_viewConfigurationTouchSlop);
+ mPagingTouchSlop = mTouchSlop * 2;
+
+ mDoubleTapTouchSlop = mTouchSlop;
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 2a041f7..1102a47 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2719,13 +2719,6 @@
return more;
}
- float alpha = child.getAlpha();
- // Bail out early if the view does not need to be drawn
- if (alpha <= ViewConfiguration.ALPHA_THRESHOLD && (child.mPrivateFlags & ALPHA_SET) == 0 &&
- !(child instanceof SurfaceView)) {
- return more;
- }
-
if (hardwareAccelerated) {
// Clear INVALIDATED flag to allow invalidation to occur during rendering, but
// retain the flag's value temporarily in the mRecreateDisplayList flag
@@ -2779,6 +2772,7 @@
}
}
+ float alpha = child.getAlpha();
if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
if (transformToApply != null || !childHasIdentityMatrix) {
int transX = 0;
@@ -2958,6 +2952,17 @@
mDrawLayers = enabled;
invalidate(true);
+ boolean flushLayers = !enabled;
+ AttachInfo info = mAttachInfo;
+ if (info != null && info.mHardwareRenderer != null &&
+ info.mHardwareRenderer.isEnabled()) {
+ if (!info.mHardwareRenderer.validate()) {
+ flushLayers = false;
+ }
+ } else {
+ flushLayers = false;
+ }
+
// We need to invalidate any child with a layer. For instance,
// if a child is backed by a hardware layer and we disable layers
// the child is marked as not dirty (flags cleared the last time
@@ -2968,6 +2973,7 @@
for (int i = 0; i < mChildrenCount; i++) {
View child = mChildren[i];
if (child.mLayerType != LAYER_TYPE_NONE) {
+ if (flushLayers) child.flushLayer();
child.invalidate(true);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2dd7ddf..7a9d82c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2389,8 +2389,6 @@
public final static int RESIZED_REPORT = 1003;
public final static int WINDOW_FOCUS_CHANGED = 1004;
public final static int DISPATCH_KEY = 1005;
- public final static int DISPATCH_POINTER = 1006;
- public final static int DISPATCH_TRACKBALL = 1007;
public final static int DISPATCH_APP_VISIBILITY = 1008;
public final static int DISPATCH_GET_NEW_SURFACE = 1009;
public final static int IME_FINISHED_EVENT = 1010;
@@ -2422,10 +2420,6 @@
return "WINDOW_FOCUS_CHANGED";
case DISPATCH_KEY:
return "DISPATCH_KEY";
- case DISPATCH_POINTER:
- return "DISPATCH_POINTER";
- case DISPATCH_TRACKBALL:
- return "DISPATCH_TRACKBALL";
case DISPATCH_APP_VISIBILITY:
return "DISPATCH_APP_VISIBILITY";
case DISPATCH_GET_NEW_SURFACE:
@@ -2591,6 +2585,10 @@
case DIE:
doDie();
break;
+ case DISPATCH_KEY: {
+ KeyEvent event = (KeyEvent)msg.obj;
+ enqueueInputEvent(event, null, 0);
+ } break;
case DISPATCH_KEY_FROM_IME: {
if (LOCAL_LOGV) Log.v(
TAG, "Dispatching key "
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 3574a0d..2b59b80 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -19,10 +19,13 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Style;
+import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -51,7 +54,6 @@
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
-import android.widget.AbsoluteLayout;
import android.widget.AbsoluteLayout.LayoutParams;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
@@ -74,7 +76,6 @@
static final String LOGTAG = "webtextview";
- private Paint mRingPaint;
private int mRingInset;
private WebView mWebView;
@@ -207,13 +208,51 @@
}
}
};
- float ringWidth = 4f * context.getResources().getDisplayMetrics().density;
mReceiver = new MyResultReceiver(mHandler);
- mRingPaint = new Paint();
- mRingPaint.setColor(0x6633b5e5);
- mRingPaint.setStrokeWidth(ringWidth);
- mRingPaint.setStyle(Style.FILL);
+ float ringWidth = 2f * context.getResources().getDisplayMetrics().density;
mRingInset = (int) ringWidth;
+ setBackgroundDrawable(new BackgroundDrawable(mRingInset));
+ setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
+ getPaddingBottom());
+ }
+
+ private static class BackgroundDrawable extends Drawable {
+
+ private Paint mPaint = new Paint();
+ private int mBorderWidth;
+ private Rect mInsetRect = new Rect();
+
+ public BackgroundDrawable(int width) {
+ mPaint = new Paint();
+ mPaint.setStrokeWidth(width);
+ mBorderWidth = width;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ mPaint.setColor(0x6633b5e5);
+ canvas.drawRect(getBounds(), mPaint);
+ mInsetRect.left = getBounds().left + mBorderWidth;
+ mInsetRect.top = getBounds().top + mBorderWidth;
+ mInsetRect.right = getBounds().right - mBorderWidth;
+ mInsetRect.bottom = getBounds().bottom - mBorderWidth;
+ mPaint.setColor(Color.WHITE);
+ canvas.drawRect(mInsetRect, mPaint);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
}
public void setAutoFillable(int queryId) {
@@ -223,35 +262,9 @@
}
@Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- if (isFocused()) {
- final int ib = getHeight() - mRingInset;
- canvas.drawRect(0, 0, getWidth(), mRingInset, mRingPaint);
- canvas.drawRect(0, ib, getWidth(), getHeight(), mRingPaint);
- canvas.drawRect(0, mRingInset, mRingInset, ib, mRingPaint);
- canvas.drawRect(getWidth() - mRingInset, mRingInset, getWidth(), ib, mRingPaint);
- }
- }
-
- private void growOrShrink(boolean grow) {
- AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams) getLayoutParams();
- if (grow) {
- lp.x -= mRingInset;
- lp.y -= mRingInset;
- lp.width += 2 * mRingInset;
- lp.height += 2 * mRingInset;
- setPadding(getPaddingLeft() + mRingInset, getPaddingTop() + mRingInset,
- getPaddingRight() + mRingInset, getPaddingBottom() + mRingInset);
- } else {
- lp.x += mRingInset;
- lp.y += mRingInset;
- lp.width -= 2 * mRingInset;
- lp.height -= 2 * mRingInset;
- setPadding(getPaddingLeft() - mRingInset, getPaddingTop() - mRingInset,
- getPaddingRight() - mRingInset, getPaddingBottom() - mRingInset);
- }
- setLayoutParams(lp);
+ public void setPadding(int left, int top, int right, int bottom) {
+ super.setPadding(left + mRingInset, top + mRingInset,
+ right + mRingInset, bottom + mRingInset);
}
@Override
@@ -555,7 +568,6 @@
} else if (!mInsideRemove) {
mWebView.setActive(false);
}
- growOrShrink(focused);
mFromFocusChange = false;
}
@@ -966,6 +978,10 @@
*/
/* package */ void setRect(int x, int y, int width, int height) {
LayoutParams lp = (LayoutParams) getLayoutParams();
+ x -= mRingInset;
+ y -= mRingInset;
+ width += 2 * mRingInset;
+ height += 2 * mRingInset;
boolean needsUpdate = false;
if (null == lp) {
lp = new LayoutParams(width, height, x, y);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index b68dec9..a284a17 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -59,6 +59,7 @@
import android.os.StrictMode;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
@@ -849,13 +850,12 @@
// the alias via which accessibility JavaScript interface is exposed
private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility";
- // JavaScript to inject the script chooser which will
- // pick the right script for the current URL
- private static final String ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT =
+ // 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 = 'https://ssl.gstatic.com/accessibility/javascript/android/AndroidScriptChooser.user.js';" +
+ " chooser.src = '%1s';" +
" document.getElementsByTagName('head')[0].appendChild(chooser);" +
" })();";
@@ -2496,11 +2496,12 @@
}
/**
- * Return the reading level scale of the WebView
+ * Compute the reading level scale of the WebView
+ * @param scale The current scale.
* @return The reading level scale.
*/
- /*package*/ float getReadingLevelScale() {
- return mZoomManager.getReadingLevelScale();
+ /*package*/ float computeReadingLevelScale(float scale) {
+ return mZoomManager.computeReadingLevelScale(scale);
}
/**
@@ -3818,7 +3819,7 @@
if (onDeviceScriptInjectionEnabled) {
ensureAccessibilityScriptInjectorInstance(false);
// neither script injected nor script injection opted out => we inject
- loadUrl(ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT);
+ 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;
@@ -3832,7 +3833,7 @@
} else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED) {
ensureAccessibilityScriptInjectorInstance(false);
// the URL provides accessibility but we still need to add our generic script
- loadUrl(ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT);
+ loadUrl(getScreenReaderInjectingJs());
} else {
Log.e(LOGTAG, "Unknown URL value for the \"axs\" URL parameter: " + axsParameterValue);
}
@@ -3854,6 +3855,17 @@
}
/**
+ * 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.
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 0f749bc..14da23e 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2514,7 +2514,7 @@
if (mSettings.isNarrowColumnLayout()) {
// In case of automatic text reflow in fixed view port mode.
mInitialViewState.mTextWrapScale =
- mWebView.getReadingLevelScale();
+ mWebView.computeReadingLevelScale(data.mScale);
}
} else {
// Scale is given such as when page is restored, use it.
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 14bdc42..8ffba64 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -316,7 +316,12 @@
* Returns the zoom scale used for reading text on a double-tap.
*/
public final float getReadingLevelScale() {
- return mDisplayDensity * mDoubleTapZoomFactor;
+ return computeScaleWithLimits(computeReadingLevelScale(getZoomOverviewScale()));
+ }
+
+ /* package */ final float computeReadingLevelScale(float scale) {
+ return Math.max(mDisplayDensity * mDoubleTapZoomFactor,
+ scale + MIN_DOUBLE_TAP_SCALE_INCREMENT);
}
public final float getInvDefaultScale() {
@@ -678,7 +683,7 @@
}
zoomToOverview();
} else {
- zoomToReadingLevelOrMore();
+ zoomToReadingLevel();
}
}
@@ -709,9 +714,8 @@
!mWebView.getSettings().getUseFixedViewport());
}
- private void zoomToReadingLevelOrMore() {
- final float zoomScale = Math.max(getReadingLevelScale(),
- mActualScale + MIN_DOUBLE_TAP_SCALE_INCREMENT);
+ private void zoomToReadingLevel() {
+ final float readingScale = getReadingLevelScale();
int left = mWebView.nativeGetBlockLeftEdge(mAnchorX, mAnchorY, mActualScale);
if (left != WebView.NO_LEFTEDGE) {
@@ -721,13 +725,13 @@
// Re-calculate the zoom center so that the new scroll x will be
// on the left edge.
if (viewLeft > 0) {
- mZoomCenterX = viewLeft * zoomScale / (zoomScale - mActualScale);
+ mZoomCenterX = viewLeft * readingScale / (readingScale - mActualScale);
} else {
mWebView.scrollBy(viewLeft, 0);
mZoomCenterX = 0;
}
}
- startZoomAnimation(zoomScale,
+ startZoomAnimation(readingScale,
!mWebView.getSettings().getUseFixedViewport());
}
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index 7ba4777..07bd918 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -145,6 +145,9 @@
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
}
}
+ public synchronized void onDataSetChangedAsync() {
+ onDataSetChanged();
+ }
public synchronized int getCount() {
int count = 0;
try {
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index d03db10..4bd7165 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -272,9 +272,11 @@
((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
+
if (!isInDictionary && looksLikeTypo) {
createMisspelledSuggestionSpan(editable, suggestionsInfo, spellCheckSpan);
}
+
editable.removeSpan(spellCheckSpan);
break;
}
@@ -295,20 +297,21 @@
}, SPELL_PAUSE_DURATION);
}
- private void createMisspelledSuggestionSpan(Editable editable,
- SuggestionsInfo suggestionsInfo, SpellCheckSpan spellCheckSpan) {
+ private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo,
+ SpellCheckSpan spellCheckSpan) {
final int start = editable.getSpanStart(spellCheckSpan);
final int end = editable.getSpanEnd(spellCheckSpan);
- if (start < 0 || end < 0) return; // span was removed in the meantime
+ if (start < 0 || end <= start) return; // span was removed in the meantime
// Other suggestion spans may exist on that region, with identical suggestions, filter
- // them out to avoid duplicates. First, filter suggestion spans on that exact region.
+ // them out to avoid duplicates.
SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class);
final int length = suggestionSpans.length;
for (int i = 0; i < length; i++) {
final int spanStart = editable.getSpanStart(suggestionSpans[i]);
final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
if (spanStart != start || spanEnd != end) {
+ // Nulled (to avoid new array allocation) if not on that exact same region
suggestionSpans[i] = null;
}
}
@@ -355,6 +358,8 @@
SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ mTextView.invalidateRegion(start, end);
}
private class SpellParser {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1fab1ca..babd8e7 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4326,15 +4326,24 @@
}
private void invalidateCursor(int a, int b, int c) {
+ if (a >= 0 || b >= 0 || c >= 0) {
+ int start = Math.min(Math.min(a, b), c);
+ int end = Math.max(Math.max(a, b), c);
+ invalidateRegion(start, end);
+ }
+ }
+
+ /**
+ * Invalidates the region of text enclosed between the start and end text offsets.
+ *
+ * @hide
+ */
+ void invalidateRegion(int start, int end) {
if (mLayout == null) {
invalidate();
} else {
- if (a >= 0 || b >= 0 || c >= 0) {
- int first = Math.min(Math.min(a, b), c);
- int last = Math.max(Math.max(a, b), c);
-
- int line = mLayout.getLineForOffset(first);
- int top = mLayout.getLineTop(line);
+ int lineStart = mLayout.getLineForOffset(start);
+ int top = mLayout.getLineTop(lineStart);
// This is ridiculous, but the descent from the line above
// can hang down into the line we really want to redraw,
@@ -4342,36 +4351,36 @@
// sure everything that needs to be redrawn really is.
// (But not the whole line above, because that would cause
// the same problem with the descenders on the line above it!)
- if (line > 0) {
- top -= mLayout.getLineDescent(line - 1);
+ if (lineStart > 0) {
+ top -= mLayout.getLineDescent(lineStart - 1);
}
- int line2;
+ int lineEnd;
- if (first == last)
- line2 = line;
+ if (start == end)
+ lineEnd = lineStart;
else
- line2 = mLayout.getLineForOffset(last);
+ lineEnd = mLayout.getLineForOffset(end);
- int bottom = mLayout.getLineTop(line2 + 1);
+ int bottom = mLayout.getLineBottom(lineEnd);
- final int horizontalPadding = getCompoundPaddingLeft();
+ final int compoundPaddingLeft = getCompoundPaddingLeft();
final int verticalPadding = getExtendedPaddingTop() + getVerticalOffset(true);
-
- // If used, the cursor drawables can have an arbitrary dimension that can go beyond
- // the invalidated lines specified above.
- for (int i = 0; i < mCursorCount; i++) {
- Rect bounds = mCursorDrawable[i].getBounds();
- top = Math.min(top, bounds.top);
- bottom = Math.max(bottom, bounds.bottom);
- // Horizontal bounds are already full width, no need to update
+
+ int left, right;
+ if (lineStart == lineEnd) {
+ left = (int) mLayout.getPrimaryHorizontal(start);
+ right = (int) (mLayout.getPrimaryHorizontal(end) + 1.0);
+ left += compoundPaddingLeft;
+ right += compoundPaddingLeft;
+ } else {
+ // Rectangle bounding box when the region spans several lines
+ left = compoundPaddingLeft;
+ right = getWidth() - getCompoundPaddingRight();
}
- invalidate(horizontalPadding + mScrollX, top + verticalPadding,
- horizontalPadding + mScrollX + getWidth() -
- getCompoundPaddingLeft() - getCompoundPaddingRight(),
- bottom + verticalPadding);
- }
+ invalidate(mScrollX + left, verticalPadding + top,
+ mScrollX + right, verticalPadding + bottom);
}
}
@@ -5904,10 +5913,10 @@
if (cursorOffsetVertical != 0) {
canvas.translate(0, -cursorOffsetVertical);
}
- invalidate(true);
+ invalidate(true); // TODO invalidate cursor region only
} else {
stopAnimation();
- invalidate(false);
+ invalidate(false); // TODO invalidate cursor region only
}
}
@@ -7729,10 +7738,8 @@
onSelectionChanged(newSelStart, newSelEnd);
}
}
-
- if (what instanceof UpdateAppearance || what instanceof ParagraphStyle
- || (what instanceof SuggestionSpan && (((SuggestionSpan)what).getFlags()
- & SuggestionSpan.FLAG_AUTO_CORRECTION) != 0)) {
+
+ if (what instanceof UpdateAppearance || what instanceof ParagraphStyle) {
if (ims == null || ims.mBatchEditNesting == 0) {
invalidate();
mHighlightPathBogus = true;
@@ -9924,6 +9931,7 @@
if (suggestionInfo.suggestionIndex == ADD_TO_DICTIONARY) {
Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
intent.putExtra("word", originalText);
+ intent.putExtra("locale", getTextServicesLocale().toString());
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
// There is no way to know if the word was indeed added. Re-check.
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 72489a2..61c0c8e 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1367,10 +1367,12 @@
/**
* Get a message and set Message.target = this.
*
- * @return message
+ * @return message or null if SM has quit
*/
public final Message obtainMessage()
{
+ if (mSmHandler == null) return null;
+
return Message.obtain(mSmHandler);
}
@@ -1378,9 +1380,11 @@
* Get a message and set Message.target = this and what
*
* @param what is the assigned to Message.what.
- * @return message
+ * @return message or null if SM has quit
*/
public final Message obtainMessage(int what) {
+ if (mSmHandler == null) return null;
+
return Message.obtain(mSmHandler, what);
}
@@ -1390,10 +1394,12 @@
*
* @param what is the assigned to Message.what.
* @param obj is assigned to Message.obj.
- * @return message
+ * @return message or null if SM has quit
*/
public final Message obtainMessage(int what, Object obj)
{
+ if (mSmHandler == null) return null;
+
return Message.obtain(mSmHandler, what, obj);
}
@@ -1404,10 +1410,13 @@
* @param what is assigned to Message.what
* @param arg1 is assigned to Message.arg1
* @param arg2 is assigned to Message.arg2
- * @return A Message object from the global pool.
+ * @return A Message object from the global pool or null if
+ * SM has quit
*/
public final Message obtainMessage(int what, int arg1, int arg2)
{
+ if (mSmHandler == null) return null;
+
return Message.obtain(mSmHandler, what, arg1, arg2);
}
@@ -1419,10 +1428,13 @@
* @param arg1 is assigned to Message.arg1
* @param arg2 is assigned to Message.arg2
* @param obj is assigned to Message.obj
- * @return A Message object from the global pool.
+ * @return A Message object from the global pool or null if
+ * SM has quit
*/
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
+ if (mSmHandler == null) return null;
+
return Message.obtain(mSmHandler, what, arg1, arg2, obj);
}
@@ -1430,6 +1442,9 @@
* Enqueue a message to this state machine.
*/
public final void sendMessage(int what) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessage(obtainMessage(what));
}
@@ -1437,6 +1452,9 @@
* Enqueue a message to this state machine.
*/
public final void sendMessage(int what, Object obj) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessage(obtainMessage(what,obj));
}
@@ -1444,6 +1462,9 @@
* Enqueue a message to this state machine.
*/
public final void sendMessage(Message msg) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessage(msg);
}
@@ -1451,6 +1472,9 @@
* Enqueue a message to this state machine after a delay.
*/
public final void sendMessageDelayed(int what, long delayMillis) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
}
@@ -1458,6 +1482,9 @@
* Enqueue a message to this state machine after a delay.
*/
public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
}
@@ -1465,6 +1492,9 @@
* Enqueue a message to this state machine after a delay.
*/
public final void sendMessageDelayed(Message msg, long delayMillis) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.sendMessageDelayed(msg, delayMillis);
}
@@ -1509,6 +1539,9 @@
* will be processed.
*/
public final void quit() {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.quit();
}
@@ -1523,6 +1556,9 @@
* @return if debugging is enabled
*/
public boolean isDbg() {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return false;
+
return mSmHandler.isDbg();
}
@@ -1532,6 +1568,9 @@
* @param dbg is true to enable debugging.
*/
public void setDbg(boolean dbg) {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
mSmHandler.setDbg(dbg);
}
@@ -1539,6 +1578,9 @@
* Start the state machine.
*/
public void start() {
+ // mSmHandler can be null if the state machine has quit.
+ if (mSmHandler == null) return;
+
/** Send the complete construction message */
mSmHandler.completeConstruction();
}
diff --git a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
index 18076c4..7317ecf 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
@@ -22,6 +22,7 @@
/** {@hide} */
interface IRemoteViewsFactory {
void onDataSetChanged();
+ oneway void onDataSetChangedAsync();
oneway void onDestroy(in Intent intent);
int getCount();
RemoteViews getViewAt(int position);
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 7724646..feba1e6 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -732,11 +732,7 @@
jcharArray text, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
-#if RTL_USE_HARFBUZZ
drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
-#else
- TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas);
-#endif
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
@@ -745,11 +741,7 @@
int start, int end,
jfloat x, jfloat y, int flags, SkPaint* paint) {
const jchar* textArray = env->GetStringChars(text, NULL);
-#if RTL_USE_HARFBUZZ
drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
-#else
- TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas);
-#endif
env->ReleaseStringChars(text, textArray);
}
@@ -770,12 +762,14 @@
value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count,
contextCount, flags);
if (value == NULL) {
- LOGE("Cannot get TextLayoutCache value");
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(textArray + start, count).string());
return ;
}
#else
- value = new TextLayoutCacheValue();
- value->computeValues(paint, textArray, start, count, contextCount, flags);
+ value = new TextLayoutCacheValue(contextCount);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ reinterpret_cast<const UChar*>(textArray), start, count, contextCount, flags);
#endif
doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), x, y, flags, paint);
}
@@ -802,13 +796,8 @@
jfloat x, jfloat y, int dirFlags, SkPaint* paint) {
jchar* chars = env->GetCharArrayElements(text, NULL);
-#if RTL_USE_HARFBUZZ
drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
count, contextCount, x, y, dirFlags, paint);
-#else
- TextLayout::drawTextRun(paint, chars + contextIndex, index - contextIndex,
- count, contextCount, dirFlags, x, y, canvas);
-#endif
env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
}
@@ -820,13 +809,8 @@
jint count = end - start;
jint contextCount = contextEnd - contextStart;
const jchar* chars = env->GetStringChars(text, NULL);
-#if RTL_USE_HARFBUZZ
drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
count, contextCount, x, y, dirFlags, paint);
-#else
- TextLayout::drawTextRun(paint, chars + contextStart, start - contextStart,
- count, contextCount, dirFlags, x, y, canvas);
-#endif
env->ReleaseStringChars(text, chars);
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 883940b..19f53d7 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -350,14 +350,10 @@
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
const jchar* textArray = env->GetCharArrayElements(text, NULL);
jfloat result = 0;
-#if RTL_USE_HARFBUZZ
+
TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
paint->getFlags(), NULL /* dont need all advances */, &result);
-#else
- // we double count, since measureText wants a byteLength
- SkScalar width = paint->measureText(textArray + index, count << 1);
- result = SkScalarToFloat(width);
-#endif
+
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
return result;
}
@@ -380,13 +376,9 @@
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
jfloat width = 0;
-#if RTL_USE_HARFBUZZ
TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
paint->getFlags(), NULL /* dont need all advances */, &width);
-#else
- width = SkScalarToFloat(paint->measureText(textArray + start, count << 1));
-#endif
env->ReleaseStringChars(text, textArray);
return width;
}
@@ -404,12 +396,9 @@
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
jfloat width = 0;
-#if RTL_USE_HARFBUZZ
TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
paint->getFlags(), NULL /* dont need all advances */, &width);
-#else
- width = SkScalarToFloat(paint->measureText(textArray, textLength << 1));
-#endif
+
env->ReleaseStringChars(text, textArray);
return width;
}
@@ -434,17 +423,9 @@
AutoJavaFloatArray autoWidths(env, widths, count);
jfloat* widthsArray = autoWidths.ptr();
-#if RTL_USE_HARFBUZZ
TextLayout::getTextRunAdvances(paint, text, 0, count, count,
paint->getFlags(), widthsArray, NULL /* dont need totalAdvance */);
-#else
- SkScalar* scalarArray = (SkScalar*)widthsArray;
- count = paint->getTextWidths(text, count << 1, scalarArray);
- for (int i = 0; i < count; i++) {
- widthsArray[i] = SkScalarToFloat(scalarArray[i]);
- }
-#endif
return count;
}
@@ -597,54 +578,11 @@
static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start,
jint count, jint flags, jint offset, jint opt) {
-#if RTL_USE_HARFBUZZ
jfloat scalarArray[count];
TextLayout::getTextRunAdvances(paint, text, start, count, count, flags,
scalarArray, NULL /* dont need totalAdvance */);
-#else
- SkScalar scalarArray[count];
- jchar buffer[count];
- // this is where we'd call harfbuzz
- // for now we just use ushape.c and widths returned from skia
-
- int widths;
- if (flags & 0x1) { // rtl, call arabic shaping in case
- UErrorCode status = U_ZERO_ERROR;
- // Use fixed length since we need to keep start and count valid
- u_shapeArabic(text + start, count, buffer, count,
- U_SHAPE_LENGTH_FIXED_SPACES_NEAR | U_SHAPE_TEXT_DIRECTION_LOGICAL |
- U_SHAPE_LETTERS_SHAPE | U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
- // we shouldn't fail unless there's an out of memory condition,
- // in which case we're hosed anyway
- for (int i = 0; i < count; ++i) {
- if (buffer[i] == 0xffff) {
- buffer[i] = 0x200b; // zero-width-space for skia
- }
- }
- widths = paint->getTextWidths(buffer, count << 1, scalarArray);
- } else {
- widths = paint->getTextWidths(text + start, count << 1, scalarArray);
- }
-
- if (widths < count) {
- // Skia operates on code points, not code units, so surrogate pairs return only one
- // value. Expand the result so we have one value per UTF-16 code unit.
-
- // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
- // leaving the remaining widths zero. Not nice.
- const jchar *chars = text + start;
- for (int i = count, p = widths - 1; --i > p;) {
- if (chars[i] >= 0xdc00 && chars[i] < 0xe000 &&
- chars[i-1] >= 0xd800 && chars[i-1] < 0xdc00) {
- scalarArray[i] = 0;
- } else {
- scalarArray[i] = scalarArray[--p];
- }
- }
- }
-#endif
jint pos = offset - start;
switch (opt) {
case AFTER:
diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h
index a41c91b..d43745f 100644
--- a/core/jni/android/graphics/RtlProperties.h
+++ b/core/jni/android/graphics/RtlProperties.h
@@ -45,9 +45,6 @@
return kRtlDebugDisabled;
}
-// Define if we want to use Harfbuzz (1) or not (0)
-#define RTL_USE_HARFBUZZ 1
-
// Define if we want (1) to have Advances debug values or not (0)
#define DEBUG_ADVANCES 0
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index e1398e9..bc30ace 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "TextLayout"
+
#include "TextLayout.h"
#include "TextLayoutCache.h"
@@ -46,211 +48,35 @@
return false;
}
-/**
- * Character-based Arabic shaping.
- *
- * We'll use harfbuzz and glyph-based shaping instead once we're set up for it.
- *
- * @context the text context
- * @start the start of the text to render
- * @count the length of the text to render, start + count must be <= contextCount
- * @contextCount the length of the context
- * @shaped where to put the shaped text, must have capacity for count uchars
- * @return the length of the shaped text, or -1 if error
- */
-int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
- jchar* shaped, UErrorCode& status) {
- SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
- jchar* buffer = tempBuffer.get();
-
- // Use fixed length since we need to keep start and count valid
- u_shapeArabic(context, contextCount, buffer, contextCount,
- U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
- U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
- U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
-
- if (U_SUCCESS(status)) {
- // trim out UNICODE_NOT_A_CHAR following ligatures, if any
- int end = 0;
- for (int i = start, e = start + count; i < e; ++i) {
- if (buffer[i] != UNICODE_NOT_A_CHAR) {
- buffer[end++] = buffer[i];
- }
- }
- count = end;
- // ALOG(LOG_INFO, "CSRTL", "start %d count %d ccount %d\n", start, count, contextCount);
- ubidi_writeReverse(buffer, count, shaped, count, UBIDI_DO_MIRRORING | UBIDI_OUTPUT_REVERSE
- | UBIDI_KEEP_BASE_COMBINING, &status);
- if (U_SUCCESS(status)) {
- return count;
- }
- }
- return -1;
-}
-
-/**
- * Basic character-based layout supporting rtl and arabic shaping.
- * Runs bidi on the text and generates a reordered, shaped line in buffer, returning
- * the length.
- * @text the text
- * @len the length of the text in uchars
- * @dir receives the resolved paragraph direction
- * @buffer the buffer to receive the reordered, shaped line. Must have capacity of
- * at least len jchars.
- * @flags line bidi flags
- * @return the length of the reordered, shaped line, or -1 if error
- */
-jint TextLayout::layoutLine(const jchar* text, jint len, jint flags, int& dir, jchar* buffer,
- UErrorCode& status) {
- static const int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING |
- UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE;
-
- UBiDiLevel bidiReq = 0;
- switch (flags) {
- case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
- case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
- case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
- case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
- case kBidi_Force_LTR: memcpy(buffer, text, len * sizeof(jchar)); return len;
- case kBidi_Force_RTL: return shapeRtlText(text, 0, len, len, buffer, status);
- }
-
- int32_t result = -1;
-
- UBiDi* bidi = ubidi_open();
- if (bidi) {
- ubidi_setPara(bidi, text, len, bidiReq, NULL, &status);
- if (U_SUCCESS(status)) {
- dir = ubidi_getParaLevel(bidi) & 0x1; // 0 if ltr, 1 if rtl
-
- int rc = ubidi_countRuns(bidi, &status);
- if (U_SUCCESS(status)) {
- // ALOG(LOG_INFO, "LAYOUT", "para bidiReq=%d dir=%d rc=%d\n", bidiReq, dir, rc);
-
- int32_t slen = 0;
- for (int i = 0; i < rc; ++i) {
- int32_t start;
- int32_t length;
- UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &start, &length);
-
- if (runDir == UBIDI_RTL) {
- slen += shapeRtlText(text + start, 0, length, length, buffer + slen, status);
- } else {
- memcpy(buffer + slen, text + start, length * sizeof(jchar));
- slen += length;
- }
- }
- if (U_SUCCESS(status)) {
- result = slen;
- }
- }
- }
- ubidi_close(bidi);
- }
-
- return result;
-}
-
-bool TextLayout::prepareText(SkPaint* paint, const jchar* text, jsize len, jint bidiFlags,
- const jchar** outText, int32_t* outBytes, jchar** outBuffer) {
- const jchar *workText = text;
- jchar *buffer = NULL;
- int dir = kDirection_LTR;
- if (needsLayout(text, len, bidiFlags)) {
- buffer =(jchar *) malloc(len * sizeof(jchar));
- if (!buffer) {
- return false;
- }
- UErrorCode status = U_ZERO_ERROR;
- len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir
- if (!U_SUCCESS(status)) {
- ALOG(LOG_WARN, "LAYOUT", "drawText error %d\n", status);
- free(buffer);
- return false; // can't render
- }
- workText = buffer; // use the shaped text
- }
-
- bool trimLeft = false;
- bool trimRight = false;
-
- SkPaint::Align horiz = paint->getTextAlign();
- switch (horiz) {
- case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break;
- case SkPaint::kCenter_Align: trimLeft = trimRight = true; break;
- case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask);
- default: break;
- }
- const jchar* workLimit = workText + len;
-
- if (trimLeft) {
- while (workText < workLimit && *workText == ' ') {
- ++workText;
- }
- }
- if (trimRight) {
- while (workLimit > workText && *(workLimit - 1) == ' ') {
- --workLimit;
- }
- }
-
- *outBytes = (workLimit - workText) << 1;
- *outText = workText;
- *outBuffer = buffer;
-
- return true;
-}
-
// Draws or gets the path of a paragraph of text on a single line, running bidi and shaping.
// This will draw if canvas is not null, otherwise path must be non-null and it will create
// a path representing the text that would have been drawn.
void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
jint bidiFlags, jfloat x, jfloat y,SkCanvas *canvas, SkPath *path) {
- const jchar *workText;
- jchar *buffer = NULL;
- int32_t workBytes;
- if (prepareText(paint, text, len, bidiFlags, &workText, &workBytes, &buffer)) {
- SkScalar x_ = SkFloatToScalar(x);
- SkScalar y_ = SkFloatToScalar(y);
- if (canvas) {
- canvas->drawText(workText, workBytes, x_, y_, *paint);
- } else {
- paint->getTextPath(workText, workBytes, x_, y_, path);
- }
- free(buffer);
+ sp<TextLayoutCacheValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+ // Return advances from the cache. Compute them if needed
+ value = TextLayoutCache::getInstance().getValue(paint, text, 0, len,
+ len, bidiFlags);
+#else
+ value = new TextLayoutCacheValue(len);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ reinterpret_cast<const UChar*>(text), 0, len, len, bidiFlags);
+#endif
+ if (value == NULL) {
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(text, len).string());
+ return ;
}
-}
-
-bool TextLayout::prepareRtlTextRun(const jchar* context, jsize start, jsize& count,
- jsize contextCount, jchar* shaped) {
- UErrorCode status = U_ZERO_ERROR;
- count = shapeRtlText(context, start, count, contextCount, shaped, status);
- if (U_SUCCESS(status)) {
- return true;
+ SkScalar x_ = SkFloatToScalar(x);
+ SkScalar y_ = SkFloatToScalar(y);
+ if (canvas) {
+ canvas->drawText(value->getGlyphs(), value->getGlyphsCount() * 2, x_, y_, *paint);
} else {
- LOGW("drawTextRun error %d\n", status);
+ paint->getTextPath(value->getGlyphs(), value->getGlyphsCount() * 2, x_, y_, path);
}
- return false;
}
-void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars,
- jint start, jint count, jint contextCount,
- int dirFlags, jfloat x, jfloat y, SkCanvas* canvas) {
-
- SkScalar x_ = SkFloatToScalar(x);
- SkScalar y_ = SkFloatToScalar(y);
-
- uint8_t rtl = dirFlags & 0x1;
- if (rtl) {
- SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(contextCount);
- if (prepareRtlTextRun(chars, start, count, contextCount, buffer.get())) {
- canvas->drawText(buffer.get(), count << 1, x_, y_, *paint);
- }
- } else {
- canvas->drawText(chars + start, count << 1, x_, y_, *paint);
- }
- }
-
void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat* resultTotalAdvance) {
@@ -260,16 +86,20 @@
value = TextLayoutCache::getInstance().getValue(paint, chars, start, count,
contextCount, dirFlags);
#else
- value = new TextLayoutCacheValue();
- value->computeValues(paint, chars, start, count, contextCount, dirFlags);
+ value = new TextLayoutCacheValue(contextCount);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ reinterpret_cast<const UChar*>(chars), start, count, contextCount, dirFlags);
#endif
- if (value != NULL) {
- if (resultAdvances) {
- memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
- }
- if (resultTotalAdvance) {
- *resultTotalAdvance = value->getTotalAdvance();
- }
+ if (value == NULL) {
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(chars + start, count).string());
+ return ;
+ }
+ if (resultAdvances) {
+ memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
+ }
+ if (resultTotalAdvance) {
+ *resultTotalAdvance = value->getTotalAdvance();
}
}
@@ -281,12 +111,6 @@
resultAdvances, &resultTotalAdvance);
}
-// Draws a paragraph of text on a single line, running bidi and shaping
-void TextLayout::drawText(SkPaint* paint, const jchar* text, jsize len,
- int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas) {
- handleText(paint, text, len, bidiFlags, x, y, canvas, NULL);
-}
-
void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
handleText(paint, text, len, bidiFlags, x, y, NULL, path);
@@ -305,14 +129,30 @@
return;
}
- SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(count);
-
- int dir = kDirection_LTR;
- UErrorCode status = U_ZERO_ERROR;
- count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status);
- if (U_SUCCESS(status)) {
- canvas->drawTextOnPathHV(buffer.get(), count << 1, *path, h_, v_, *paint);
+ sp<TextLayoutCacheValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+ value = TextLayoutCache::getInstance().getValue(paint, text, 0, count,
+ count, bidiFlags);
+#else
+ value = new TextLayoutCacheValue(count);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ reinterpret_cast<const UChar*>(text), 0, count, count, bidiFlags);
+#endif
+ if (value == NULL) {
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(text, count).string());
+ return ;
}
+
+ // Save old text encoding
+ SkPaint::TextEncoding oldEncoding = paint->getTextEncoding();
+ // Define Glyph encoding
+ paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint);
+
+ // Get back old encoding
+ paint->setTextEncoding(oldEncoding);
}
void TextLayout::computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index 9df3829..1dabe32 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -62,13 +62,6 @@
class TextLayout {
public:
- /*
- * Draws a unidirectional run of text.
- */
- static void drawTextRun(SkPaint* paint, const jchar* chars,
- jint start, jint count, jint contextCount,
- int dirFlags, jfloat x, jfloat y, SkCanvas* canvas);
-
static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat* resultTotalAdvance);
@@ -77,29 +70,16 @@
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat& resultTotalAdvance);
- static void drawText(SkPaint* paint, const jchar* text, jsize len,
- jint bidiFlags, jfloat x, jfloat y, SkCanvas* canvas);
-
static void getTextPath(SkPaint* paint, const jchar* text, jsize len,
jint bidiFlags, jfloat x, jfloat y, SkPath* path);
static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
int bidiFlags, jfloat hOffset, jfloat vOffset,
SkPath* path, SkCanvas* canvas);
-
- static bool prepareText(SkPaint* paint, const jchar* text, jsize len, jint bidiFlags,
- const jchar** outText, int32_t* outBytes, jchar** outBuffer);
-
- static bool prepareRtlTextRun(const jchar* context, jsize start, jsize& count,
- jsize contextCount, jchar* shaped);
-
private:
static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
- static int shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
- jchar* shaped, UErrorCode& status);
- static jint layoutLine(const jchar* text, jint len, jint flags, int &dir, jchar* buffer,
- UErrorCode &status);
+
static void handleText(SkPaint* paint, const jchar* text, jsize len,
int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas, SkPath* path);
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index f1c3101..81bf4d5 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -34,10 +34,11 @@
#if USE_TEXT_LAYOUT_CACHE
ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutCache);
- ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
#endif
+ ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
+
//--------------------------------------------------------------------------------------------------
TextLayoutCache::TextLayoutCache() :
@@ -549,8 +550,8 @@
LOGD("Shaping Script Run with");
LOGD(" -- isRTL = %d", isRTL);
LOGD(" -- HB script = %d", mShaperItem.item.script);
- LOGD(" -- startFontRun = %d", startScriptRun);
- LOGD(" -- endFontRun = %d", endScriptRun);
+ LOGD(" -- startFontRun = %d", int(startScriptRun));
+ LOGD(" -- endFontRun = %d", int(endScriptRun));
LOGD(" -- countFontRun = %d", countScriptRun);
LOGD(" -- run = '%s'", String8(chars + startScriptRun, countScriptRun).string());
LOGD(" -- string = '%s'", String8(chars, count).string());
@@ -572,12 +573,12 @@
if (isRTL) {
endScriptRun = startScriptRun;
#if DEBUG_GLYPHS
- LOGD("Updated endScriptRun = %d", endScriptRun);
+ LOGD("Updated endScriptRun = %d", int(endScriptRun));
#endif
} else {
startScriptRun = endScriptRun;
#if DEBUG_GLYPHS
- LOGD("Updated startScriptRun = %d", startScriptRun);
+ LOGD("Updated startScriptRun = %d", int(startScriptRun));
#endif
}
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 3b45ccd..f61795d 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -107,6 +107,12 @@
return status_t(n);
}
+ status_t status = mReceiver.requestNextVsync();
+ if (status) {
+ LOGW("Failed to request next vsync, status=%d", status);
+ return status;
+ }
+
if (!mFdCallbackRegistered) {
int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
handleReceiveCallback, this);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 426f4f7..5860658 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -44,7 +44,7 @@
#include <SkiaColorFilter.h>
#include <Rect.h>
-#include <TextLayout.h>
+#include <TextLayoutCache.h>
namespace android {
@@ -487,66 +487,45 @@
static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
-#if RTL_USE_HARFBUZZ
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, flags);
if (value == NULL) {
- LOGE("Cannot get TextLayoutCache value");
- return ;
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(text, count).string());
+ return;
}
#else
- value = new TextLayoutCacheValue();
- value->computeValues(paint, text, 0, count, count, flags);
+ value = new TextLayoutCacheValue(count);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ text, 0, count, count, flags);
#endif
const jchar* glyphs = value->getGlyphs();
size_t glyphsCount = value->getGlyphsCount();
int bytesCount = glyphsCount * sizeof(jchar);
renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint);
-#else
- const jchar *workText;
- jchar* buffer = NULL;
- int32_t workBytes;
- if (TextLayout::prepareText(paint, text, count, flags, &workText, &workBytes, &buffer)) {
- renderer->drawText((const char*) workText, workBytes, count, x, y, paint);
- free(buffer);
- }
-#endif
}
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
jint start, jint count, jint contextCount, jfloat x, jfloat y,
int flags, SkPaint* paint) {
-#if RTL_USE_HARFBUZZ
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
value = TextLayoutCache::getInstance().getValue(paint, text, start, count, contextCount, flags);
if (value == NULL) {
- LOGE("Cannot get TextLayoutCache value");
- return ;
+ LOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(text + start, count).string());
+ return;
}
#else
- value = new TextLayoutCacheValue();
- value->computeValues(paint, text, start, count, contextCount, flags);
+ value = new TextLayoutCacheValue(count);
+ TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ text, start, count, contextCount, flags);
#endif
const jchar* glyphs = value->getGlyphs();
size_t glyphsCount = value->getGlyphsCount();
int bytesCount = glyphsCount * sizeof(jchar);
renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint);
-#else
- uint8_t rtl = flags & 0x1;
- if (rtl) {
- SkAutoSTMalloc<80, jchar> buffer(contextCount);
- jchar* shaped = buffer.get();
- if (TextLayout::prepareRtlTextRun(text, start, count, contextCount, shaped)) {
- renderer->drawText((const char*) shaped, count << 1, count, x, y, paint);
- } else {
- LOGW("drawTextRun error");
- }
- } else {
- renderer->drawText((const char*) (text + start), count << 1, count, x, y, paint);
- }
-#endif
}
static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
@@ -719,6 +698,10 @@
LayerRenderer::destroyLayerDeferred(layer);
}
+static void android_view_GLES20Canvas_flushLayer(JNIEnv* env, jobject clazz, Layer* layer) {
+ LayerRenderer::flushLayer(layer);
+}
+
static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y, SkPaint* paint) {
renderer->drawLayer(layer, x, y, paint);
@@ -869,6 +852,7 @@
{ "nSetTextureLayerTransform", "(II)V", (void*) android_view_GLES20Canvas_setTextureLayerTransform },
{ "nDestroyLayer", "(I)V", (void*) android_view_GLES20Canvas_destroyLayer },
{ "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred },
+ { "nFlushLayer", "(I)V", (void*) android_view_GLES20Canvas_flushLayer },
{ "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer },
{ "nCopyLayer", "(II)Z", (void*) android_view_GLES20Canvas_copyLayer },
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back_ime.xml b/core/res/res/drawable/silent_mode_indicator.xml
similarity index 74%
rename from packages/SystemUI/res/drawable/ic_sysbar_back_ime.xml
rename to core/res/res/drawable/silent_mode_indicator.xml
index 248496d..c4e129f 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_back_ime.xml
+++ b/core/res/res/drawable/silent_mode_indicator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -15,7 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true" android:drawable="@drawable/ic_sysbar_back_ime_pressed" />
- <item android:drawable="@drawable/ic_sysbar_back_ime_default" />
+ <item android:state_selected="false" android:drawable="@android:color/transparent" />
+ <item android:state_selected="true" android:drawable="@drawable/tab_selected_holo" />
</selector>
-
diff --git a/core/res/res/layout/global_actions_item.xml b/core/res/res/layout/global_actions_item.xml
index 13ab985..694301e 100644
--- a/core/res/res/layout/global_actions_item.xml
+++ b/core/res/res/layout/global_actions_item.xml
@@ -22,7 +22,7 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
- android:paddingLeft="11dip"
+ android:paddingLeft="16dip"
android:paddingTop="6dip"
android:paddingBottom="6dip"
>
@@ -30,7 +30,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
- android:layout_marginRight="9dip"
+ android:layout_marginRight="16dip"
/>
<LinearLayout
diff --git a/core/res/res/layout/global_actions_silent_mode.xml b/core/res/res/layout/global_actions_silent_mode.xml
new file mode 100644
index 0000000..18b4715
--- /dev/null
+++ b/core/res/res/layout/global_actions_silent_mode.xml
@@ -0,0 +1,103 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:orientation="horizontal"
+ >
+
+ <LinearLayout
+ android:id="@+id/option1"
+ android:layout_width="64dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/actionBarItemBackground"
+ android:contentDescription="@string/silent_mode_silent"
+ android:focusable="true"
+ >
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="6dp"
+ android:src="@drawable/ic_audio_vol_mute"
+ android:scaleType="center"
+ android:duplicateParentState="true"
+ android:background="@drawable/silent_mode_indicator"
+ />
+ </LinearLayout>
+ <!-- Spacer -->
+ <View android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:visibility="invisible"/>
+
+ <LinearLayout
+ android:id="@+id/option2"
+ android:layout_width="64dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/actionBarItemBackground"
+ android:contentDescription="@string/silent_mode_vibrate"
+ android:focusable="true"
+ >
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="6dp"
+ android:src="@drawable/ic_audio_ring_notif_vibrate"
+ android:scaleType="center"
+ android:duplicateParentState="true"
+ android:background="@drawable/silent_mode_indicator"
+ />
+ </LinearLayout>
+
+ <!-- Spacer -->
+ <View android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:visibility="invisible"/>
+
+ <LinearLayout
+ android:id="@+id/option3"
+ android:layout_width="64dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/actionBarItemBackground"
+ android:contentDescription="@string/silent_mode_ring"
+ android:focusable="true"
+ >
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="6dp"
+ android:src="@drawable/ic_audio_vol"
+ android:scaleType="center"
+ android:duplicateParentState="true"
+ android:background="@drawable/silent_mode_indicator"
+ />
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 326f186..3ab72f4 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -747,4 +747,9 @@
<!-- Name of screensaver components to look for if none has been chosen by the user -->
<string name="config_defaultDreamComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+
+ <!-- Base "touch slop" value used by ViewConfiguration as a
+ movement threshold where scrolling should begin. -->
+ <dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7ad1d53..6f115b3 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -286,6 +286,12 @@
<string name="screen_lock">Screen lock</string>
<!-- Button to turn off the phone, within the Phone Options dialog -->
<string name="power_off">Power off</string>
+ <!-- Spoken description for ringer silent option. [CHAR LIMIT=NONE] -->
+ <string name="silent_mode_silent">Ringer off</string>
+ <!-- Spoken description for ringer vibrate option. [CHAR LIMIT=NONE] -->
+ <string name="silent_mode_vibrate">Ringer vibrate</string>
+ <!-- Spoken description for ringer normal option. [CHAR LIMIT=NONE] -->
+ <string name="silent_mode_ring">Ringer on</string>
<!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. -->
<string name="shutdown_progress">Shutting down\u2026</string>
diff --git a/data/fonts/DroidSansArmenian.ttf b/data/fonts/DroidSansArmenian.ttf
index 62f67e0..6fafa54 100644
--- a/data/fonts/DroidSansArmenian.ttf
+++ b/data/fonts/DroidSansArmenian.ttf
Binary files differ
diff --git a/data/fonts/DroidSansGeorgian.ttf b/data/fonts/DroidSansGeorgian.ttf
index 743ae66..3a2e9fb 100644
--- a/data/fonts/DroidSansGeorgian.ttf
+++ b/data/fonts/DroidSansGeorgian.ttf
Binary files differ
diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd
index 5abffb3..5cf1a59 100644
--- a/docs/html/guide/topics/graphics/2d-graphics.jd
+++ b/docs/html/guide/topics/graphics/2d-graphics.jd
@@ -130,9 +130,8 @@
<p class="note"><strong>Note: </strong> In order to request an invalidate from a thread other than your main
Activity's thread, you must call <code>{@link android.view.View#postInvalidate()}</code>.</p>
-<p>Also read <a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a>
-for a guide to extending a View class, and <a href="2d-graphics.html">2D Graphics: Drawables</a> for
-information on using Drawable objects like images from your resources and other primitive shapes.</p>
+<p>For information about extending the {@link android.view.View} class, read
+<a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a>.</p>
<p>For a sample application, see the Snake game, in the SDK samples folder:
<code><your-sdk-directory>/samples/Snake/</code>.</p>
@@ -188,7 +187,7 @@
<p>This document discusses the basics of using Drawable objects to draw graphics and how to use a
couple subclasses of the Drawable class. For information on using Drawables to do frame-by-frame
-animation, see <a href="{@docRoot}guide/topics/animation/drawable-animation.html">Drawable
+animation, see <a href="{@docRoot}guide/topics/graphics/drawable-animation.html">Drawable
Animation</a>.</p>
<p>A {@link android.graphics.drawable.Drawable} is a general abstraction for "something that can be
diff --git a/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf b/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf
new file mode 100644
index 0000000..598a27e
--- /dev/null
+++ b/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf b/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf
new file mode 100644
index 0000000..6ef41dd
--- /dev/null
+++ b/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf b/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf
new file mode 100755
index 0000000..e56d2377
--- /dev/null
+++ b/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf
Binary files differ
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index 8d07c0e..dccc164 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -94,6 +94,20 @@
*/
ssize_t getEvents(Event* events, size_t count);
+ /*
+ * setVsyncRate() sets the Event::VSync delivery rate. A value of
+ * 1 returns every Event::VSync. A value of 2 returns every other event,
+ * etc... a value of 0 returns no event unless requestNextVsync() has
+ * been called.
+ */
+ status_t setVsyncRate(uint32_t count);
+
+ /*
+ * requestNextVsync() schedules the next Event::VSync. It has no effect
+ * if the vsync rate is > 0.
+ */
+ status_t requestNextVsync();
+
private:
sp<IDisplayEventConnection> mEventConnection;
sp<BitTube> mDataChannel;
diff --git a/include/gui/IDisplayEventConnection.h b/include/gui/IDisplayEventConnection.h
index 8728bb5..86247de 100644
--- a/include/gui/IDisplayEventConnection.h
+++ b/include/gui/IDisplayEventConnection.h
@@ -33,9 +33,27 @@
class IDisplayEventConnection : public IInterface
{
public:
+
DECLARE_META_INTERFACE(DisplayEventConnection);
+ /*
+ * getDataChannel() returns a BitTube where to receive the events from
+ */
virtual sp<BitTube> getDataChannel() const = 0;
+
+ /*
+ * setVsyncRate() sets the vsync event delivery rate. A value of
+ * 1 returns every vsync events. A value of 2 returns every other events,
+ * etc... a value of 0 returns no event unless requestNextVsync() has
+ * been called.
+ */
+ virtual void setVsyncRate(uint32_t count) = 0;
+
+ /*
+ * requestNextVsync() schedules the next vsync event. It has no effect
+ * if the vsync rate is > 0.
+ */
+ virtual void requestNextVsync() = 0; // asynchronous
};
// ----------------------------------------------------------------------------
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 3b29a11..fee1feb 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -58,6 +58,26 @@
return mDataChannel->getFd();
}
+status_t DisplayEventReceiver::setVsyncRate(uint32_t count) {
+ if (int32_t(count) < 0)
+ return BAD_VALUE;
+
+ if (mEventConnection != NULL) {
+ mEventConnection->setVsyncRate(count);
+ return NO_ERROR;
+ }
+ return NO_INIT;
+}
+
+status_t DisplayEventReceiver::requestNextVsync() {
+ if (mEventConnection != NULL) {
+ mEventConnection->requestNextVsync();
+ return NO_ERROR;
+ }
+ return NO_INIT;
+}
+
+
ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
size_t count) {
ssize_t size = mDataChannel->read(events, sizeof(events[0])*count);
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index 44127fb..887d176 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -32,6 +32,8 @@
enum {
GET_DATA_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
+ SET_VSYNC_RATE,
+ REQUEST_NEXT_VSYNC
};
class BpDisplayEventConnection : public BpInterface<IDisplayEventConnection>
@@ -49,6 +51,19 @@
remote()->transact(GET_DATA_CHANNEL, data, &reply);
return new BitTube(reply);
}
+
+ virtual void setVsyncRate(uint32_t count) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
+ data.writeInt32(count);
+ remote()->transact(SET_VSYNC_RATE, data, &reply);
+ }
+
+ virtual void requestNextVsync() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
+ remote()->transact(REQUEST_NEXT_VSYNC, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
IMPLEMENT_META_INTERFACE(DisplayEventConnection, "android.gui.DisplayEventConnection");
@@ -65,6 +80,16 @@
channel->writeToParcel(reply);
return NO_ERROR;
} break;
+ case SET_VSYNC_RATE: {
+ CHECK_INTERFACE(IDisplayEventConnection, data, reply);
+ setVsyncRate(data.readInt32());
+ return NO_ERROR;
+ } break;
+ case REQUEST_NEXT_VSYNC: {
+ CHECK_INTERFACE(IDisplayEventConnection, data, reply);
+ requestNextVsync();
+ return NO_ERROR;
+ } break;
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 9bfc94c..95e0a18 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -38,7 +38,7 @@
external/skia/src/ports \
external/skia/include/utils
- LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
+ LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DGL_GLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 38d1130..48e4247 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -66,6 +66,7 @@
mHasNPot = hasExtension("GL_OES_texture_npot");
mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch");
+ mHasDiscardFramebuffer = hasExtension("GL_EXT_discard_framebuffer");
const char* vendor = (const char*) glGetString(GL_VENDOR);
EXT_LOGD("Vendor: %s", vendor);
@@ -80,6 +81,7 @@
inline bool hasNPot() const { return mHasNPot; }
inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
inline bool needsHighpTexCoords() const { return mNeedsHighpTexCoords; }
+ inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
bool hasExtension(const char* extension) const {
const String8 s(extension);
@@ -98,6 +100,7 @@
bool mHasNPot;
bool mNeedsHighpTexCoords;
bool mHasFramebufferFetch;
+ bool mHasDiscardFramebuffer;
}; // class Extensions
}; // namespace uirenderer
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 6bf6004..e2d9ea3 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -305,8 +305,10 @@
LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
layer->getWidth(), layer->getHeight(), layer->getFbo());
- if (layer->getFbo()) {
- Caches::getInstance().fboCache.put(layer->getFbo());
+ GLuint fbo = layer->getFbo();
+ if (fbo) {
+ flushLayer(layer);
+ Caches::getInstance().fboCache.put(fbo);
}
if (!Caches::getInstance().layerCache.put(layer)) {
@@ -331,6 +333,26 @@
}
}
+void LayerRenderer::flushLayer(Layer* layer) {
+#ifdef GL_EXT_discard_framebuffer
+ GLuint fbo = layer->getFbo();
+ if (layer && fbo) {
+ // If possible, discard any enqueud operations on deferred
+ // rendering architectures
+ if (Caches::getInstance().extensions.hasDiscardFramebuffer()) {
+ GLuint previousFbo;
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
+
+ GLenum attachments = GL_COLOR_ATTACHMENT0;
+ if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, &attachments);
+
+ if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+ }
+ }
+#endif
+}
+
bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
Caches& caches = Caches::getInstance();
if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize &&
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 6104301..72d8d81 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -61,6 +61,7 @@
bool isOpaque, GLenum renderTarget, float* transform);
ANDROID_API static void destroyLayer(Layer* layer);
ANDROID_API static void destroyLayerDeferred(Layer* layer);
+ ANDROID_API static void flushLayer(Layer* layer);
ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap);
private:
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 81c053e..1d7b99d 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -615,6 +615,11 @@
}
if (fboLayer) {
+ // Note: No need to use glDiscardFramebufferEXT() since we never
+ // create/compose layers that are not on screen with this
+ // code path
+ // See LayerRenderer::destroyLayer(Layer*)
+
// Detach the texture from the FBO
glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index e9c3c5e..84bca9c 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -364,7 +364,7 @@
typedef float4 rs_quaternion;
#define RS_PACKED __attribute__((packed, aligned(4)))
-#define NULL ((const void *)0)
+#define NULL ((void *)0)
#if (defined(RS_VERSION) && (RS_VERSION >= 14))
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 3b55246..c201417 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -21,6 +21,7 @@
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
import android.app.ActivityManagerNative;
+import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.bluetooth.BluetoothA2dp;
@@ -319,6 +320,8 @@
private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000;
// previous volume adjustment direction received by checkForRingerModeChange()
private int mPrevVolDirection = AudioManager.ADJUST_SAME;
+ // Keyguard manager proxy
+ private KeyguardManager mKeyguardManager;
///////////////////////////////////////////////////////////////////////////
// Construction
@@ -503,9 +506,10 @@
streamType = getActiveStreamType(suggestedStreamType);
}
- // Play sounds on STREAM_RING only.
+ // Play sounds on STREAM_RING only and if lock screen is not on.
if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
- ((STREAM_VOLUME_ALIAS[streamType] != AudioSystem.STREAM_RING))) {
+ ((STREAM_VOLUME_ALIAS[streamType] != AudioSystem.STREAM_RING)
+ || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
@@ -2659,6 +2663,8 @@
sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SHARED_MSG, SENDMSG_NOOP,
0, 0, null, 0);
+ mKeyguardManager =
+ (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
resetBluetoothSco();
getBluetoothHeadset();
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 8d71dcf..4c70e9d 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1735,6 +1735,9 @@
/**
* Called to indicate the video size
*
+ * The video size (width and height) could be 0 if there was no video,
+ * no display surface was set, or the value was not determined yet.
+ *
* @param mp the MediaPlayer associated with this callback
* @param width the width of the video
* @param height the height of the video
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 759d05a..964cb1f 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -2021,9 +2021,9 @@
mLock.unlock();
- // Initially make sure we have at least 128 bytes for the sniff
+ // Initially make sure we have at least 192 KB for the sniff
// to complete without blocking.
- static const size_t kMinBytesForSniffing = 128;
+ static const size_t kMinBytesForSniffing = 192 * 1024;
off64_t metaDataSize = -1ll;
for (;;) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 70523c1..e471f73 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -16,6 +16,11 @@
#include "include/AMRExtractor.h"
#include "include/AVIExtractor.h"
+
+#if CHROMIUM_AVAILABLE
+#include "include/DataUriSource.h"
+#endif
+
#include "include/MP3Extractor.h"
#include "include/MPEG4Extractor.h"
#include "include/WAVExtractor.h"
@@ -136,6 +141,10 @@
return NULL;
}
source = new NuCachedSource2(httpSource);
+# if CHROMIUM_AVAILABLE
+ } else if (!strncasecmp("data:", uri, 5)) {
+ source = new DataUriSource(uri);
+#endif
} else {
// Assume it's a filename.
source = new FileSource(uri);
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
index 6573e3c..63775f1 100644
--- a/media/libstagefright/chromium_http/Android.mk
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -3,8 +3,9 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- ChromiumHTTPDataSource.cpp \
- support.cpp \
+ DataUriSource.cpp \
+ ChromiumHTTPDataSource.cpp \
+ support.cpp
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
diff --git a/media/libstagefright/chromium_http/DataUriSource.cpp b/media/libstagefright/chromium_http/DataUriSource.cpp
new file mode 100644
index 0000000..ecf3fa1
--- /dev/null
+++ b/media/libstagefright/chromium_http/DataUriSource.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#include <include/DataUriSource.h>
+
+#include <net/base/data_url.h>
+#include <googleurl/src/gurl.h>
+
+
+namespace android {
+
+DataUriSource::DataUriSource(const char *uri) :
+ mDataUri(uri),
+ mInited(NO_INIT) {
+
+ // Copy1: const char *uri -> String8 mDataUri.
+ std::string mimeTypeStr, unusedCharsetStr, dataStr;
+ // Copy2: String8 mDataUri -> std::string
+ const bool ret = net::DataURL::Parse(
+ GURL(std::string(mDataUri.string())),
+ &mimeTypeStr, &unusedCharsetStr, &dataStr);
+ // Copy3: std::string dataStr -> AString mData
+ mData.setTo(dataStr.data(), dataStr.length());
+ mInited = ret ? OK : UNKNOWN_ERROR;
+
+ // The chromium data url implementation defaults to using "text/plain"
+ // if no mime type is specified. We prefer to leave this unspecified
+ // instead, since the mime type is sniffed in most cases.
+ if (mimeTypeStr != "text/plain") {
+ mMimeType = mimeTypeStr.c_str();
+ }
+}
+
+ssize_t DataUriSource::readAt(off64_t offset, void *out, size_t size) {
+ if (mInited != OK) {
+ return mInited;
+ }
+
+ const off64_t length = mData.size();
+ if (offset >= length) {
+ return UNKNOWN_ERROR;
+ }
+
+ const char *dataBuf = mData.c_str();
+ const size_t bytesToCopy =
+ offset + size >= length ? (length - offset) : size;
+
+ if (bytesToCopy > 0) {
+ memcpy(out, dataBuf + offset, bytesToCopy);
+ }
+
+ return bytesToCopy;
+}
+
+} // namespace android
diff --git a/media/libstagefright/include/DataUriSource.h b/media/libstagefright/include/DataUriSource.h
new file mode 100644
index 0000000..d223c06
--- /dev/null
+++ b/media/libstagefright/include/DataUriSource.h
@@ -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.
+ */
+
+#ifndef DATA_URI_SOURCE_H_
+
+#define DATA_URI_SOURCE_H_
+
+#include <stdio.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+class DataUriSource : public DataSource {
+public:
+ DataUriSource(const char *uri);
+
+ virtual status_t initCheck() const {
+ return mInited;
+ }
+
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+ virtual status_t getSize(off64_t *size) {
+ if (mInited != OK) {
+ return mInited;
+ }
+
+ *size = mData.size();
+ return OK;
+ }
+
+ virtual String8 getUri() {
+ return mDataUri;
+ }
+
+ virtual String8 getMIMEType() const {
+ return mMimeType;
+ }
+
+protected:
+ virtual ~DataUriSource() {
+ // Nothing to delete.
+ }
+
+private:
+ const String8 mDataUri;
+
+ String8 mMimeType;
+ // Use AString because individual bytes may not be valid UTF8 chars.
+ AString mData;
+ status_t mInited;
+
+ // Disallow copy and assign.
+ DataUriSource(const DataUriSource &);
+ DataUriSource &operator=(const DataUriSource &);
+};
+
+} // namespace android
+
+#endif // DATA_URI_SOURCE_H_
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
index 3c8d05a..e788c17 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
@@ -353,6 +353,8 @@
AudioEffect vc = null;
MediaPlayer mp = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -411,6 +413,7 @@
probe.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
@@ -425,6 +428,8 @@
MediaPlayer mp = null;
AudioEffect rvb = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -495,6 +500,7 @@
probe.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
index 757bbc5..bc9c48d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
@@ -198,6 +198,8 @@
AudioEffect vc = null;
MediaPlayer mp = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -254,6 +256,7 @@
probe.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
@@ -268,6 +271,8 @@
MediaPlayer mp = null;
AudioEffect rvb = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -336,6 +341,7 @@
probe.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
index e0cf51d..b0bf654 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
@@ -200,6 +200,8 @@
AudioEffect vc = null;
MediaPlayer mp = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -264,6 +266,7 @@
vc.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
@@ -276,6 +279,8 @@
AudioEffect vc = null;
MediaPlayer mp = null;
AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerMode();
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -393,6 +398,7 @@
vc.release();
}
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+ am.setRingerMode(ringerMode);
}
assertTrue(msg, result);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java
index 3c08138..4181903 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java
@@ -709,7 +709,7 @@
blockTillPreviewCompletes.acquire();
- final String fileName = mVideoEditor.getPath() + "\test.3gp";
+ final String fileName = mVideoEditor.getPath() + "/test.3gp";
final int height = MediaProperties.HEIGHT_480;
final int bitrate = MediaProperties.BITRATE_512K;
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 1ebed1f..4ea2c31 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -115,6 +115,11 @@
0x200000038=0x03000701:0x03010701:0x03020701;
</string>
+ <!-- Default for Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION_URL -->
+ <string name="def_accessibility_screen_reader_url" translatable="false">
+ https://ssl.gstatic.com/accessibility/javascript/android/AndroidScriptChooser.user.js
+ </string>
+
<!-- Default for Settings.Secure.TOUCH_EXPLORATION_ENABLED -->
<bool name="def_touch_exploration_enabled">false</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 6258652..a6a3303 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -63,7 +63,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 72;
+ private static final int DATABASE_VERSION = 74;
private Context mContext;
@@ -961,6 +961,7 @@
+ " VALUES(?,?);");
loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
R.bool.def_accessibility_speak_password);
+ db.setTransactionSuccessful();
} finally {
db.endTransaction();
if (stmt != null) stmt.close();
@@ -968,6 +969,39 @@
upgradeVersion = 72;
}
+ if (upgradeVersion == 72) {
+ // update vibration settings
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT OR REPLACE INTO system(name,value)"
+ + " VALUES(?,?);");
+ loadBooleanSetting(stmt, Settings.System.VIBRATE_IN_SILENT,
+ R.bool.def_vibrate_in_silent);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ upgradeVersion = 73;
+ }
+
+ if (upgradeVersion == 73) {
+ // URL from which WebView loads a JavaScript based screen-reader.
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT INTO secure(name,value) VALUES(?,?);");
+ loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
+ R.string.def_accessibility_screen_reader_url);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ upgradeVersion = 74;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -1508,6 +1542,9 @@
loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
R.bool.def_accessibility_speak_password);
+
+ loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
+ R.string.def_accessibility_screen_reader_url);
} finally {
if (stmt != null) stmt.close();
}
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_default.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
similarity index 100%
rename from packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_default.png
rename to packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_pressed.png
deleted file mode 100644
index 4757125..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
similarity index 100%
rename from packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png
rename to packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_pressed.png
deleted file mode 100644
index 0cd05a3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_default.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_default.png
rename to packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_pressed.png
deleted file mode 100644
index 3e59c8d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
index 111f9a4..8e231d0 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
@@ -32,7 +32,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
- android:paddingBottom="@*android:dimen/status_bar_height"
+ android:layout_marginBottom="@*android:dimen/status_bar_height"
android:clipToPadding="false"
android:clipChildren="false">
@@ -69,13 +69,12 @@
</FrameLayout>
- <View android:id="@+id/recents_dismiss_button"
- android:layout_width="80px"
+ <com.android.systemui.recent.StatusBarTouchProxy
+ android:id="@+id/status_bar_touch_proxy"
+ android:layout_width="match_parent"
android:layout_height="@*android:dimen/status_bar_height"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
- android:background="@drawable/ic_sysbar_back_ime"
- android:contentDescription="@string/status_bar_accessibility_dismiss_recents"
/>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
index 6cd8899..d51f9c8 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
@@ -15,20 +15,29 @@
* limitations under the License.
-->
-<LinearLayout
+<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="horizontal"
- android:gravity="bottom"
>
+ <View
+ android:layout_height="@*android:dimen/status_bar_height"
+ android:layout_width="match_parent"
+ android:background="@drawable/status_bar_ticker_background"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentBottom="true"
+ android:clickable="false"
+ />
+
<ImageView
android:id="@+id/large_icon"
android:layout_width="@android:dimen/notification_large_icon_height"
android:layout_height="@android:dimen/notification_large_icon_width"
android:scaleType="center"
android:visibility="gone"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentBottom="true"
/>
<FrameLayout
@@ -36,6 +45,8 @@
android:layout_weight="1"
android:layout_height="@*android:dimen/status_bar_height"
android:layout_width="match_parent"
- android:background="@drawable/status_bar_ticker_background"
+ android:layout_toRightOf="@id/large_icon"
+ android:layout_alignParentBottom="true"
+ android:layout_alignWithParentIfMissing="true"
/>
-</LinearLayout>
+</RelativeLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 8bfd711..4aec22c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -68,10 +68,11 @@
private View mRecentsScrim;
private View mRecentsNoApps;
private ViewGroup mRecentsContainer;
+ private StatusBarTouchProxy mStatusBarTouchProxy;
private boolean mShowing;
private Choreographer mChoreo;
- private View mRecentsDismissButton;
+ OnRecentsPanelVisibilityChangedListener mVisibilityChangedListener;
private RecentTasksLoader mRecentTasksLoader;
private ArrayList<TaskDescription> mRecentTaskDescriptions;
@@ -81,8 +82,8 @@
private int mThumbnailWidth;
private boolean mFitThumbnailToXY;
- public void setRecentTasksLoader(RecentTasksLoader loader) {
- mRecentTasksLoader = loader;
+ public static interface OnRecentsPanelVisibilityChangedListener {
+ public void onRecentsPanelVisibilityChanged(boolean visible);
}
private final class OnLongClickDelegate implements View.OnLongClickListener {
@@ -171,15 +172,18 @@
return super.onKeyUp(keyCode, event);
}
- public boolean isInContentArea(int x, int y) {
- // use mRecentsContainer's exact bounds to determine horizontal position
- final int l = mRecentsContainer.getLeft();
- final int r = mRecentsContainer.getRight();
- final int t = mRecentsContainer.getTop();
- final int b = mRecentsContainer.getBottom();
+ private boolean pointInside(int x, int y, View v) {
+ final int l = v.getLeft();
+ final int r = v.getRight();
+ final int t = v.getTop();
+ final int b = v.getBottom();
return x >= l && x < r && y >= t && y < b;
}
+ public boolean isInContentArea(int x, int y) {
+ return pointInside(x, y, mRecentsContainer) || pointInside(x, y, mStatusBarTouchProxy);
+ }
+
public void show(boolean show, boolean animate) {
show(show, animate, null);
}
@@ -278,7 +282,6 @@
public void onAnimationStart(Animator animation) {
}
-
/**
* We need to be aligned at the bottom. LinearLayout can't do this, so instead,
* let LinearLayout do all the hard work, and then shift everything down to the bottom.
@@ -312,6 +315,29 @@
public void setBar(StatusBar bar) {
mBar = bar;
+
+ }
+
+ public void setStatusBarView(View statusBarView) {
+ if (mStatusBarTouchProxy != null) {
+ mStatusBarTouchProxy.setStatusBar(statusBarView);
+ }
+ }
+
+ public void setRecentTasksLoader(RecentTasksLoader loader) {
+ mRecentTasksLoader = loader;
+ }
+
+ public void setOnVisibilityChangedListener(OnRecentsPanelVisibilityChangedListener l) {
+ mVisibilityChangedListener = l;
+
+ }
+
+ public void setVisibility(int visibility) {
+ if (mVisibilityChangedListener != null) {
+ mVisibilityChangedListener.onRecentsPanelVisibilityChanged(visibility == VISIBLE);
+ }
+ super.setVisibility(visibility);
}
public RecentsPanelView(Context context, AttributeSet attrs) {
@@ -335,6 +361,7 @@
super.onFinishInflate();
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
+ mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
mListAdapter = new TaskDescriptionAdapter(mContext);
if (mRecentsContainer instanceof RecentsHorizontalScrollView){
RecentsHorizontalScrollView scrollView
@@ -355,14 +382,6 @@
mRecentsScrim = findViewById(R.id.recents_bg_protect);
mRecentsNoApps = findViewById(R.id.recents_no_apps);
mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
- mRecentsDismissButton = findViewById(R.id.recents_dismiss_button);
- if (mRecentsDismissButton != null) {
- mRecentsDismissButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- hide(true);
- }
- });
- }
// In order to save space, we make the background texture repeat in the Y direction
if (mRecentsScrim != null && mRecentsScrim.getBackground() instanceof BitmapDrawable) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/StatusBarTouchProxy.java b/packages/SystemUI/src/com/android/systemui/recent/StatusBarTouchProxy.java
new file mode 100644
index 0000000..ded114f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/StatusBarTouchProxy.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recent;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+
+public class StatusBarTouchProxy extends FrameLayout {
+
+ private View mStatusBar;
+
+ public StatusBarTouchProxy(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setStatusBar(View statusBar) {
+ mStatusBar = statusBar;
+ }
+
+ public boolean onTouchEvent (MotionEvent event) {
+ return mStatusBar.dispatchTouchEvent(event);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index bf2d5e8..f8dfa8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -62,6 +62,8 @@
private static final int MSG_TOGGLE_RECENT_APPS = 11 << MSG_SHIFT;
+ private static final int MSG_SET_NAVIGATION_ICON_HINTS = 13 << MSG_SHIFT;
+
private StatusBarIconList mList;
private Callbacks mCallbacks;
private Handler mHandler = new H();
@@ -90,6 +92,7 @@
public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
public void setHardKeyboardStatus(boolean available, boolean enabled);
public void toggleRecentApps();
+ public void setNavigationIconHints(int hints);
}
public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -196,6 +199,13 @@
}
}
+ public void setNavigationIconHints(int hints) {
+ synchronized (mList) {
+ mHandler.removeMessages(MSG_SET_NAVIGATION_ICON_HINTS);
+ mHandler.obtainMessage(MSG_SET_NAVIGATION_ICON_HINTS, hints, 0, null).sendToTarget();
+ }
+ }
+
private final class H extends Handler {
public void handleMessage(Message msg) {
final int what = msg.what & MSG_MASK;
@@ -265,6 +275,9 @@
case MSG_TOGGLE_RECENT_APPS:
mCallbacks.toggleRecentApps();
break;
+ case MSG_SET_NAVIGATION_ICON_HINTS:
+ mCallbacks.setNavigationIconHints(msg.arg1);
+ break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 97a1855..69a247d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -18,6 +18,8 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
@@ -31,6 +33,7 @@
import android.view.ViewGroup;
import android.view.Surface;
import android.view.WindowManager;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import java.io.FileDescriptor;
@@ -61,6 +64,7 @@
boolean mHidden, mLowProfile, mShowMenu;
int mDisabledFlags = 0;
+ int mNavigationIconHints = 0;
public View getRecentsButton() {
return mCurrentView.findViewById(R.id.recent_apps);
@@ -112,6 +116,34 @@
}
};
+ public void setNavigationIconHints(int hints) {
+ setNavigationIconHints(hints, false);
+ }
+
+ public void setNavigationIconHints(int hints, boolean force) {
+ if (!force && hints == mNavigationIconHints) return;
+
+ if (DEBUG) {
+ android.widget.Toast.makeText(mContext,
+ "Navigation icon hints = " + hints,
+ 500).show();
+ }
+
+ mNavigationIconHints = hints;
+
+ getBackButton().setAlpha(
+ (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_NOP)) ? 0.5f : 1.0f);
+ getHomeButton().setAlpha(
+ (0 != (hints & StatusBarManager.NAVIGATION_HINT_HOME_NOP)) ? 0.5f : 1.0f);
+ getRecentsButton().setAlpha(
+ (0 != (hints & StatusBarManager.NAVIGATION_HINT_RECENT_NOP)) ? 0.5f : 1.0f);
+
+ ((ImageView)getBackButton()).setImageResource(
+ (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT))
+ ? R.drawable.ic_sysbar_back_ime
+ : R.drawable.ic_sysbar_back);
+ }
+
public void setDisabledFlags(int disabledFlags) {
setDisabledFlags(disabledFlags, false);
}
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 3c9d12c..5a1e3f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -32,6 +32,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.Configuration;
+import android.inputmethodservice.InputMethodService;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -229,6 +230,8 @@
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+ private int mNavigationIconHints = 0;
+
private class ExpandedDialog extends Dialog {
ExpandedDialog(Context context) {
super(context, com.android.internal.R.style.Theme_Translucent_NoTitleBar);
@@ -1541,6 +1544,17 @@
}
@Override // CommandQueue
+ public void setNavigationIconHints(int hints) {
+ if (hints == mNavigationIconHints) return;
+
+ mNavigationIconHints = hints;
+
+ if (mNavigationBarView != null) {
+ mNavigationBarView.setNavigationIconHints(hints);
+ }
+ }
+
+ @Override // CommandQueue
public void setSystemUiVisibility(int vis) {
final int old = mSystemUiVisibility;
final int diff = vis ^ old;
@@ -1590,8 +1604,16 @@
if (showMenu) setLightsOn(true);
}
- // Not supported
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition) { }
+ @Override
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+ boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS)
+ || ((vis & InputMethodService.IME_VISIBLE) != 0);
+
+ mCommandQueue.setNavigationIconHints(
+ altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
+ : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
+ }
+
@Override
public void setHardKeyboardStatus(boolean available, boolean enabled) { }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index b919aec..9919d825 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -88,7 +88,8 @@
public class TabletStatusBar extends StatusBar implements
HeightReceiver.OnBarHeightChangedListener,
- InputMethodsPanel.OnHardKeyboardEnabledChangeListener {
+ InputMethodsPanel.OnHardKeyboardEnabledChangeListener,
+ RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
public static final boolean DEBUG = false;
public static final boolean DEBUG_COMPAT_HELP = false;
public static final String TAG = "TabletStatusBar";
@@ -143,6 +144,7 @@
View mHomeButton;
View mMenuButton;
View mRecentButton;
+ private boolean mAltBackButtonEnabledForIme;
ViewGroup mFeedbackIconArea; // notification icons, IME icon, compat icon
InputMethodButton mInputMethodSwitchButton;
@@ -193,6 +195,8 @@
// used to notify status bar for suppressing notification LED
private boolean mPanelSlightlyVisible;
+ private int mNavigationIconHints = 0;
+
public Context getContext() { return mContext; }
protected void addPanelWindows() {
@@ -310,12 +314,11 @@
mRecentsPanel = (RecentsPanelView) View.inflate(context,
R.layout.status_bar_recent_panel, null);
mRecentsPanel.setVisibility(View.GONE);
- mRecentsPanel.setSystemUiVisibility(View.STATUS_BAR_DISABLE_BACK);
mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
mRecentsPanel));
+ mRecentsPanel.setOnVisibilityChangedListener(this);
mRecentsPanel.setRecentTasksLoader(mRecentTasksLoader);
mRecentTasksLoader.setRecentsPanel(mRecentsPanel);
- mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel);
lp = new WindowManager.LayoutParams(
(int) res.getDimension(R.dimen.status_bar_recents_width),
@@ -334,6 +337,7 @@
WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
mRecentsPanel.setBar(this);
+ mRecentsPanel.setStatusBarView(mStatusBarView);
// Input methods Panel
mInputMethodsPanel = (InputMethodsPanel) View.inflate(context,
@@ -342,7 +346,7 @@
mInputMethodsPanel.setOnTouchListener(new TouchOutsideListener(
MSG_CLOSE_INPUT_METHODS_PANEL, mInputMethodsPanel));
mInputMethodsPanel.setImeSwitchButton(mInputMethodSwitchButton);
- mStatusBarView.setIgnoreChildren(3, mInputMethodSwitchButton, mInputMethodsPanel);
+ mStatusBarView.setIgnoreChildren(2, mInputMethodSwitchButton, mInputMethodsPanel);
lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
@@ -365,7 +369,7 @@
MSG_CLOSE_COMPAT_MODE_PANEL, mCompatModePanel));
mCompatModePanel.setTrigger(mCompatModeButton);
mCompatModePanel.setVisibility(View.GONE);
- mStatusBarView.setIgnoreChildren(4, mCompatModeButton, mCompatModePanel);
+ mStatusBarView.setIgnoreChildren(3, mCompatModeButton, mCompatModePanel);
lp = new WindowManager.LayoutParams(
250,
ViewGroup.LayoutParams.WRAP_CONTENT,
@@ -431,6 +435,10 @@
}
}
+ public View getStatusBarView() {
+ return mStatusBarView;
+ }
+
protected View makeStatusBarView() {
final Context context = mContext;
@@ -514,6 +522,16 @@
// don't wait for these transitions; we just want icons to fade in/out, not move around
lt.setDuration(LayoutTransition.CHANGE_APPEARING, 0);
lt.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 0);
+ lt.addTransitionListener(new LayoutTransition.TransitionListener() {
+ public void endTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType) {
+ // ensure the menu button doesn't stick around on the status bar after it's been
+ // removed
+ mBarContents.invalidate();
+ }
+ public void startTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType) {}
+ });
mNavigationArea.setLayoutTransition(lt);
// no multi-touch on the nav buttons
mNavigationArea.setMotionEventSplittingEnabled(false);
@@ -1082,6 +1100,31 @@
}
}
+ @Override // CommandQueue
+ public void setNavigationIconHints(int hints) {
+ if (hints == mNavigationIconHints) return;
+
+ if (DEBUG) {
+ android.widget.Toast.makeText(mContext,
+ "Navigation icon hints = " + hints,
+ 500).show();
+ }
+
+ mNavigationIconHints = hints;
+
+ mBackButton.setAlpha(
+ (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_NOP)) ? 0.5f : 1.0f);
+ mHomeButton.setAlpha(
+ (0 != (hints & StatusBarManager.NAVIGATION_HINT_HOME_NOP)) ? 0.5f : 1.0f);
+ mRecentButton.setAlpha(
+ (0 != (hints & StatusBarManager.NAVIGATION_HINT_RECENT_NOP)) ? 0.5f : 1.0f);
+
+ mBackButton.setImageResource(
+ (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT))
+ ? R.drawable.ic_sysbar_back_ime
+ : R.drawable.ic_sysbar_back);
+ }
+
private void notifyUiVisibilityChanged() {
try {
mWindowManager.statusBarVisibilityChanged(mSystemUiVisibility);
@@ -1185,24 +1228,15 @@
(vis & InputMethodService.IME_ACTIVE) != 0);
updateNotificationIcons();
mInputMethodsPanel.setImeToken(token);
- int res;
- switch (backDisposition) {
- case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
- res = R.drawable.ic_sysbar_back;
- break;
- case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
- res = R.drawable.ic_sysbar_back_ime;
- break;
- case InputMethodService.BACK_DISPOSITION_DEFAULT:
- default:
- if ((vis & InputMethodService.IME_VISIBLE) != 0) {
- res = R.drawable.ic_sysbar_back_ime;
- } else {
- res = R.drawable.ic_sysbar_back;
- }
- break;
- }
- mBackButton.setImageResource(res);
+
+ boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS)
+ || ((vis & InputMethodService.IME_VISIBLE) != 0);
+ mAltBackButtonEnabledForIme = altBack;
+
+ mCommandQueue.setNavigationIconHints(
+ altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
+ : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
+
if (FAKE_SPACE_BAR) {
mFakeSpaceBar.setVisibility(((vis & InputMethodService.IME_VISIBLE) != 0)
? View.VISIBLE : View.GONE);
@@ -1210,6 +1244,14 @@
}
@Override
+ public void onRecentsPanelVisibilityChanged(boolean visible) {
+ boolean altBack = visible || mAltBackButtonEnabledForIme;
+ mCommandQueue.setNavigationIconHints(
+ altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
+ : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
+ }
+
+ @Override
public void setHardKeyboardStatus(boolean available, boolean enabled) {
if (DEBUG) {
Slog.d(TAG, "Set hard keyboard status: available=" + available
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
index 7d11251..877a40e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
@@ -46,10 +46,11 @@
if (TabletStatusBar.DEBUG) {
Slog.d(TabletStatusBar.TAG, "TabletStatusBarView intercepting touch event: " + ev);
}
+ // do not close the recents panel here- the intended behavior is that recents is dismissed
+ // on touch up when clicking on status bar buttons
+ // TODO: should we be closing the notification panel and input methods panel?
mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL);
mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL);
- mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_RECENTS_PANEL);
- mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_RECENTS_PANEL);
mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_INPUT_METHODS_PANEL);
mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_INPUT_METHODS_PANEL);
mHandler.removeMessages(TabletStatusBar.MSG_STOP_TICKER);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index 6045e31..e93a32b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -73,6 +73,8 @@
private StatusBarNotification[] mQueue = new StatusBarNotification[QUEUE_LENGTH];
private int mQueuePos;
+ private final int mLargeIconHeight;
+
private TabletStatusBar mBar;
private LayoutTransition mLayoutTransition;
@@ -81,6 +83,9 @@
public TabletTicker(TabletStatusBar bar) {
mBar = bar;
mContext = bar.getContext();
+ final Resources res = mContext.getResources();
+ mLargeIconHeight = res.getDimensionPixelSize(
+ android.R.dimen.notification_large_icon_height);
}
public void add(IBinder key, StatusBarNotification notification) {
@@ -209,8 +214,6 @@
final Resources res = mContext.getResources();
final FrameLayout view = new FrameLayout(mContext);
final int width = res.getDimensionPixelSize(R.dimen.notification_ticker_width);
- final int height = res.getDimensionPixelSize(
- android.R.dimen.notification_large_icon_height);
int windowFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
@@ -219,7 +222,7 @@
} else {
windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
}
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, mLargeIconHeight,
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, windowFlags,
PixelFormat.TRANSLUCENT);
lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
@@ -297,6 +300,16 @@
if (n.largeIcon != null) {
largeIcon.setImageBitmap(n.largeIcon);
largeIcon.setVisibility(View.VISIBLE);
+ final ViewGroup.LayoutParams lp = largeIcon.getLayoutParams();
+ final int statusBarHeight = mBar.getStatusBarHeight();
+ if (n.largeIcon.getHeight() <= statusBarHeight) {
+ // for smallish largeIcons, it looks a little odd to have them floating halfway up
+ // the ticker, so we vertically center them in the status bar area instead
+ lp.height = statusBarHeight;
+ } else {
+ lp.height = mLargeIconHeight;
+ }
+ largeIcon.setLayoutParams(lp);
}
if (CLICKABLE_TICKER) {
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 3fc53aa..38c85bb 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -56,7 +56,7 @@
private static final String TAG = "GlobalActions";
- private static final boolean SHOW_SILENT_TOGGLE = false;
+ private static final boolean SHOW_SILENT_TOGGLE = true;
private final Context mContext;
private final AudioManager mAudioManager;
@@ -64,7 +64,7 @@
private ArrayList<Action> mItems;
private AlertDialog mDialog;
- private ToggleAction mSilentModeToggle;
+ private SilentModeAction mSilentModeAction;
private ToggleAction mAirplaneModeOn;
private MyAdapter mAdapter;
@@ -115,39 +115,7 @@
* @return A new dialog.
*/
private AlertDialog createDialog() {
- mSilentModeToggle = new ToggleAction(
- R.drawable.ic_audio_vol_mute,
- R.drawable.ic_audio_vol,
- R.string.global_action_toggle_silent_mode,
- R.string.global_action_silent_mode_on_status,
- R.string.global_action_silent_mode_off_status) {
-
- void willCreate() {
- mEnabledIconResId =
- mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE
- ? R.drawable.ic_audio_ring_notif_vibrate
- : R.drawable.ic_audio_vol_mute;
- }
-
- void onToggle(boolean on) {
- if (on) {
- mAudioManager.setRingerMode((Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.VIBRATE_IN_SILENT, 1) == 1)
- ? AudioManager.RINGER_MODE_VIBRATE
- : AudioManager.RINGER_MODE_SILENT);
- } else {
- mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
- }
- }
-
- public boolean showDuringKeyguard() {
- return true;
- }
-
- public boolean showBeforeProvisioning() {
- return false;
- }
- };
+ mSilentModeAction = new SilentModeAction(mAudioManager, mHandler);
mAirplaneModeOn = new ToggleAction(
R.drawable.ic_lock_airplane_mode,
@@ -191,15 +159,7 @@
mItems = new ArrayList<Action>();
- // silent mode
- if (SHOW_SILENT_TOGGLE) {
- mItems.add(mSilentModeToggle);
- }
-
- // next: airplane mode
- mItems.add(mAirplaneModeOn);
-
- // last: power off
+ // first: power off
mItems.add(
new SinglePressAction(
com.android.internal.R.drawable.ic_lock_power_off,
@@ -219,15 +179,23 @@
}
});
+ // next: airplane mode
+ mItems.add(mAirplaneModeOn);
+
+ // last: silent mode
+ if (SHOW_SILENT_TOGGLE) {
+ mItems.add(mSilentModeAction);
+ }
+
mAdapter = new MyAdapter();
final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);
ab.setAdapter(mAdapter, this)
- .setInverseBackgroundForced(true)
- .setTitle(R.string.global_actions);
+ .setInverseBackgroundForced(true);
final AlertDialog dialog = ab.create();
+ dialog.getListView().setItemsCanFocus(true);
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
dialog.setOnDismissListener(this);
@@ -238,8 +206,6 @@
private void prepareDialog() {
final boolean silentModeOn =
mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
- mSilentModeToggle.updateState(
- silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
mAirplaneModeOn.updateState(mAirplaneState);
mAdapter.notifyDataSetChanged();
if (mKeyguardShowing) {
@@ -247,20 +213,28 @@
} else {
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
}
+ if (SHOW_SILENT_TOGGLE) {
+ IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ mContext.registerReceiver(mRingerModeReceiver, filter);
+ }
}
/** {@inheritDoc} */
public void onDismiss(DialogInterface dialog) {
+ if (SHOW_SILENT_TOGGLE) {
+ mContext.unregisterReceiver(mRingerModeReceiver);
+ }
}
/** {@inheritDoc} */
public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
+ if (!(mAdapter.getItem(which) instanceof SilentModeAction)) {
+ dialog.dismiss();
+ }
mAdapter.getItem(which).onPress();
}
-
/**
* The adapter used for the list within the global actions dialog, taking
* into account whether the keyguard is showing via
@@ -381,9 +355,7 @@
public View create(
Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
- View v = (convertView != null) ?
- convertView :
- inflater.inflate(R.layout.global_actions_item, parent, false);
+ View v = inflater.inflate(R.layout.global_actions_item, parent, false);
ImageView icon = (ImageView) v.findViewById(R.id.icon);
TextView messageView = (TextView) v.findViewById(R.id.message);
@@ -460,27 +432,31 @@
LayoutInflater inflater) {
willCreate();
- View v = (convertView != null) ?
- convertView :
- inflater.inflate(R
+ View v = inflater.inflate(R
.layout.global_actions_item, parent, false);
ImageView icon = (ImageView) v.findViewById(R.id.icon);
TextView messageView = (TextView) v.findViewById(R.id.message);
TextView statusView = (TextView) v.findViewById(R.id.status);
+ final boolean enabled = isEnabled();
- messageView.setText(mMessageResId);
+ if (messageView != null) {
+ messageView.setText(mMessageResId);
+ messageView.setEnabled(enabled);
+ }
boolean on = ((mState == State.On) || (mState == State.TurningOn));
- icon.setImageDrawable(context.getResources().getDrawable(
- (on ? mEnabledIconResId : mDisabledIconResid)));
- statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
- statusView.setVisibility(View.VISIBLE);
+ if (icon != null) {
+ icon.setImageDrawable(context.getResources().getDrawable(
+ (on ? mEnabledIconResId : mDisabledIconResid)));
+ icon.setEnabled(enabled);
+ }
- final boolean enabled = isEnabled();
- messageView.setEnabled(enabled);
- statusView.setEnabled(enabled);
- icon.setEnabled(enabled);
+ if (statusView != null) {
+ statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
+ statusView.setVisibility(View.VISIBLE);
+ statusView.setEnabled(enabled);
+ }
v.setEnabled(enabled);
return v;
@@ -518,6 +494,70 @@
}
}
+ private static class SilentModeAction implements Action, View.OnClickListener {
+
+ private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
+
+ private final AudioManager mAudioManager;
+ private final Handler mHandler;
+
+ SilentModeAction(AudioManager audioManager, Handler handler) {
+ mAudioManager = audioManager;
+ mHandler = handler;
+ }
+
+ private int ringerModeToIndex(int ringerMode) {
+ // They just happen to coincide
+ return ringerMode;
+ }
+
+ private int indexToRingerMode(int index) {
+ // They just happen to coincide
+ return index;
+ }
+
+ public View create(Context context, View convertView, ViewGroup parent,
+ LayoutInflater inflater) {
+ View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
+
+ int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
+ for (int i = 0; i < 3; i++) {
+ View itemView = v.findViewById(ITEM_IDS[i]);
+ itemView.setSelected(selectedIndex == i);
+ // Set up click handler
+ itemView.setTag(i);
+ itemView.setOnClickListener(this);
+ }
+ return v;
+ }
+
+ public void onPress() {
+ }
+
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ public boolean showBeforeProvisioning() {
+ return false;
+ }
+
+ public boolean isEnabled() {
+ return true;
+ }
+
+ void willCreate() {
+ }
+
+ public void onClick(View v) {
+ if (!(v.getTag() instanceof Integer)) return;
+
+ int index = (Integer) v.getTag();
+ mAudioManager.setRingerMode(indexToRingerMode(index));
+ mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
+ }
+ }
+
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -549,13 +589,27 @@
}
};
+ private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
+ mHandler.sendEmptyMessage(MESSAGE_REFRESH);
+ }
+ }
+ };
+
private static final int MESSAGE_DISMISS = 0;
+ private static final int MESSAGE_REFRESH = 1;
+ private static final int DIALOG_DISMISS_DELAY = 300; // ms
+
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_DISMISS) {
if (mDialog != null) {
mDialog.dismiss();
}
+ } else if (msg.what == MESSAGE_REFRESH) {
+ mAdapter.notifyDataSetChanged();
}
}
};
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
index de7547b..f204070 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
@@ -49,7 +49,7 @@
// Whether the volume keys should be handled by keyguard. If true, then
// they will be handled here for specific media types such as music, otherwise
// the audio service will bring up the volume dialog.
- private static final boolean KEYGUARD_MANAGES_VOLUME = false;
+ private static final boolean KEYGUARD_MANAGES_VOLUME = true;
// This is a faster way to draw the background on devices without hardware acceleration
Drawable mBackgroundDrawable = new Drawable() {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index dfb1b07..92260d6 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3213,10 +3213,7 @@
}
final int preferredRotation;
- if (mHdmiPlugged) {
- // Ignore sensor when plugged into HDMI.
- preferredRotation = mHdmiRotation;
- } else if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) {
+ if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) {
// Ignore sensor when lid switch is open and rotation is forced.
preferredRotation = mLidOpenRotation;
} else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR
@@ -3235,6 +3232,10 @@
// enable 180 degree rotation while docked.
preferredRotation = mDeskDockEnablesAccelerometer
? sensorRotation : mDeskDockRotation;
+ } else if (mHdmiPlugged) {
+ // Ignore sensor when plugged into HDMI.
+ // Note that the dock orientation overrides the HDMI orientation.
+ preferredRotation = mHdmiRotation;
} else if ((mAccelerometerDefault != 0 /* implies not rotation locked */
&& (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
|| orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED))
@@ -3477,6 +3478,9 @@
WindowManager.LayoutParams.FLAG_DIM_BEHIND
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
mBootMsgDialog.getWindow().setDimAmount(1);
+ WindowManager.LayoutParams lp = mBootMsgDialog.getWindow().getAttributes();
+ lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+ mBootMsgDialog.getWindow().setAttributes(lp);
mBootMsgDialog.setCancelable(false);
mBootMsgDialog.show();
}
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 2af5103..4f81178 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -24,9 +24,9 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.Intent.FilterComparison;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.content.Intent.FilterComparison;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -39,6 +39,8 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -74,6 +76,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
class AppWidgetService extends IAppWidgetService.Stub
{
@@ -805,6 +808,45 @@
id.host.callbacks = null;
}
}
+
+ // If the host is unavailable, then we call the associated
+ // RemoteViewsFactory.onDataSetChanged() directly
+ if (id.host.callbacks == null) {
+ Set<FilterComparison> keys = mRemoteViewsServicesAppWidgets.keySet();
+ for (FilterComparison key : keys) {
+ if (mRemoteViewsServicesAppWidgets.get(key).contains(id.appWidgetId)) {
+ Intent intent = key.getIntent();
+
+ final ServiceConnection conn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ IRemoteViewsFactory cb =
+ IRemoteViewsFactory.Stub.asInterface(service);
+ try {
+ cb.onDataSetChangedAsync();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ } catch (RuntimeException e) {
+ e.printStackTrace();
+ }
+ mContext.unbindService(this);
+ }
+ @Override
+ public void onServiceDisconnected(android.content.ComponentName name) {
+ // Do nothing
+ }
+ };
+
+ // Bind to the service and call onDataSetChanged()
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+ }
}
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 3c65255..16643ff 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -1078,7 +1078,6 @@
mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
== WifiManager.WIFI_MODE_FULL_HIGH_PERF);
} else {
- mWifiStateMachine.requestCmWakeLock();
mWifiStateMachine.setDriverStart(false);
}
} else {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index b5edc0a..6c11953 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1932,8 +1932,9 @@
// should be left as-is.
replyChainEnd = -1;
}
-
- } else if (target.resultTo != null) {
+
+ } else if (target.resultTo != null && (below == null
+ || below.task == target.task)) {
// If this activity is sending a reply to a previous
// activity, we can't do anything with it now until
// we reach the start of the reply chain.
@@ -1963,6 +1964,8 @@
replyChainEnd = targetI;
}
ActivityRecord p = null;
+ if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index "
+ + targetI + " to " + replyChainEnd);
for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
p = mHistory.get(srcPos);
if (p.finishing) {
@@ -1981,6 +1984,8 @@
if (replyChainEnd < 0) {
replyChainEnd = targetI;
}
+ if (DEBUG_TASKS) Slog.v(TAG, "Reparenting task at index "
+ + targetI + " to " + replyChainEnd);
for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
ActivityRecord p = mHistory.get(srcPos);
if (p.finishing) {
@@ -2002,6 +2007,7 @@
p.setTask(task, null, false);
mHistory.add(lastReparentPos, p);
if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
+ + " from " + srcPos + " to " + lastReparentPos
+ " in to resetting task " + task);
mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken);
mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
@@ -2031,6 +2037,11 @@
}
}
}
+
+ } else if (below != null && below.task != target.task) {
+ // We hit the botton of a task; the reply chain can't
+ // pass through it.
+ replyChainEnd = -1;
}
target = below;
diff --git a/services/surfaceflinger/DisplayEventConnection.cpp b/services/surfaceflinger/DisplayEventConnection.cpp
index a0aa9c0..77ecbd2 100644
--- a/services/surfaceflinger/DisplayEventConnection.cpp
+++ b/services/surfaceflinger/DisplayEventConnection.cpp
@@ -25,6 +25,7 @@
#include "SurfaceFlinger.h"
#include "DisplayEventConnection.h"
+#include "EventThread.h"
// ---------------------------------------------------------------------------
@@ -33,30 +34,38 @@
// ---------------------------------------------------------------------------
DisplayEventConnection::DisplayEventConnection(
- const sp<SurfaceFlinger>& flinger)
- : mFlinger(flinger), mChannel(new BitTube())
+ const sp<EventThread>& eventThread)
+ : mEventThread(eventThread), mChannel(new BitTube())
{
}
DisplayEventConnection::~DisplayEventConnection() {
- mFlinger->cleanupDisplayEventConnection(this);
+ mEventThread->unregisterDisplayEventConnection(this);
}
void DisplayEventConnection::onFirstRef() {
- // nothing to do here for now.
+ // NOTE: mEventThread doesn't hold a strong reference on us
+ mEventThread->registerDisplayEventConnection(this);
}
sp<BitTube> DisplayEventConnection::getDataChannel() const {
return mChannel;
}
+void DisplayEventConnection::setVsyncRate(uint32_t count) {
+ mEventThread->setVsyncRate(count, this);
+}
+
+void DisplayEventConnection::requestNextVsync() {
+ mEventThread->requestNextVsync(this);
+}
+
status_t DisplayEventConnection::postEvent(const DisplayEventReceiver::Event& event)
{
ssize_t size = mChannel->write(&event, sizeof(DisplayEventReceiver::Event));
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/DisplayEventConnection.h b/services/surfaceflinger/DisplayEventConnection.h
index 46cf64b..cc3ee36 100644
--- a/services/surfaceflinger/DisplayEventConnection.h
+++ b/services/surfaceflinger/DisplayEventConnection.h
@@ -32,13 +32,13 @@
// ---------------------------------------------------------------------------
class BitTube;
-class SurfaceFlinger;
+class EventThread;
// ---------------------------------------------------------------------------
class DisplayEventConnection : public BnDisplayEventConnection {
public:
- DisplayEventConnection(const sp<SurfaceFlinger>& flinger);
+ DisplayEventConnection(const sp<EventThread>& flinger);
status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -46,8 +46,10 @@
virtual ~DisplayEventConnection();
virtual void onFirstRef();
virtual sp<BitTube> getDataChannel() const;
+ virtual void setVsyncRate(uint32_t count);
+ virtual void requestNextVsync(); // asynchronous
- sp<SurfaceFlinger> const mFlinger;
+ sp<EventThread> const mEventThread;
sp<BitTube> const mChannel;
};
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 42477a9..dc39f88 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -47,7 +47,8 @@
status_t EventThread::registerDisplayEventConnection(
const sp<DisplayEventConnection>& connection) {
Mutex::Autolock _l(mLock);
- mDisplayEventConnections.add(connection);
+ ConnectionInfo info;
+ mDisplayEventConnections.add(connection, info);
mCondition.signal();
return NO_ERROR;
}
@@ -55,44 +56,97 @@
status_t EventThread::unregisterDisplayEventConnection(
const wp<DisplayEventConnection>& connection) {
Mutex::Autolock _l(mLock);
- mDisplayEventConnections.remove(connection);
+ mDisplayEventConnections.removeItem(connection);
mCondition.signal();
return NO_ERROR;
}
-status_t EventThread::removeDisplayEventConnection(
+void EventThread::removeDisplayEventConnection(
const wp<DisplayEventConnection>& connection) {
Mutex::Autolock _l(mLock);
- mDisplayEventConnections.remove(connection);
- return NO_ERROR;
+ mDisplayEventConnections.removeItem(connection);
+}
+
+EventThread::ConnectionInfo* EventThread::getConnectionInfoLocked(
+ const wp<DisplayEventConnection>& connection) {
+ ssize_t index = mDisplayEventConnections.indexOfKey(connection);
+ if (index < 0) return NULL;
+ return &mDisplayEventConnections.editValueAt(index);
+}
+
+void EventThread::setVsyncRate(uint32_t count,
+ const wp<DisplayEventConnection>& connection) {
+ if (int32_t(count) >= 0) { // server must protect against bad params
+ Mutex::Autolock _l(mLock);
+ ConnectionInfo* info = getConnectionInfoLocked(connection);
+ if (info) {
+ info->count = (count == 0) ? -1 : count;
+ mCondition.signal();
+ }
+ }
+}
+
+void EventThread::requestNextVsync(
+ const wp<DisplayEventConnection>& connection) {
+ Mutex::Autolock _l(mLock);
+ ConnectionInfo* info = getConnectionInfoLocked(connection);
+ if (info) {
+ if (info->count < 0) {
+ info->count = 0;
+ }
+ mCondition.signal();
+ }
}
bool EventThread::threadLoop() {
nsecs_t timestamp;
DisplayEventReceiver::Event vsync;
- SortedVector<wp<DisplayEventConnection> > displayEventConnections;
+ KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > displayEventConnections;
{ // scope for the lock
Mutex::Autolock _l(mLock);
do {
// wait for listeners
- while (!mDisplayEventConnections.size()) {
+ do {
+ bool waitForNextVsync = false;
+ size_t count = mDisplayEventConnections.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const ConnectionInfo& info(
+ mDisplayEventConnections.valueAt(i));
+ if (info.count >= 1) {
+ // continuous mode
+ waitForNextVsync = true;
+ } else {
+ // one-shot event
+ if (info.count >= -1) {
+ ConnectionInfo& info(
+ mDisplayEventConnections.editValueAt(i));
+ info.count--;
+ if (info.count == -1) {
+ // fired this time around
+ waitForNextVsync = true;
+ }
+ }
+ }
+ }
+
+ if (waitForNextVsync)
+ break;
+
mCondition.wait(mLock);
- }
+ } while(true);
// wait for vsync
mLock.unlock();
timestamp = mHw.waitForVSync();
mLock.lock();
+ mDeliveredEvents++;
// make sure we still have some listeners
} while (!mDisplayEventConnections.size());
-
// dispatch vsync events to listeners...
- mDeliveredEvents++;
-
vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
vsync.header.timestamp = timestamp;
vsync.vsync.count = mDeliveredEvents;
@@ -104,9 +158,30 @@
const size_t count = displayEventConnections.size();
for (size_t i=0 ; i<count ; i++) {
- sp<DisplayEventConnection> conn(displayEventConnections.itemAt(i).promote());
+ sp<DisplayEventConnection> conn(displayEventConnections.keyAt(i).promote());
// make sure the connection didn't die
if (conn != NULL) {
+
+ const ConnectionInfo& info(
+ displayEventConnections.valueAt(i));
+
+ if ((info.count > 1) && (mDeliveredEvents % info.count)) {
+ // continuous event, but not time to send this event yet
+ continue;
+ } else if (info.count < -1) {
+ // disabled event
+ continue;
+ } else if (info.count == 0) {
+ // impossible by construction. but we prefer to be safe.
+ continue;
+ }
+
+ // here, either:
+ // count = -1 : one-shot scheduled this time around
+ // count = 1 : continuous not rate-limited
+ // count > 1 : continuous, rate-limited
+ // Note: count == 0 is not possible by construction
+
status_t err = conn->postEvent(vsync);
if (err == -EAGAIN || err == -EWOULDBLOCK) {
// The destination doesn't accept events anymore, it's probably
@@ -118,12 +193,12 @@
// handle any other error on the pipe as fatal. the only
// reasonable thing to do is to clean-up this connection.
// The most common error we'll get here is -EPIPE.
- removeDisplayEventConnection(displayEventConnections.itemAt(i));
+ removeDisplayEventConnection(displayEventConnections.keyAt(i));
}
} else {
// somehow the connection is dead, but we still have it in our list
// just clean the list.
- removeDisplayEventConnection(displayEventConnections.itemAt(i));
+ removeDisplayEventConnection(displayEventConnections.keyAt(i));
}
}
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 4872c2b..35bd299 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -24,7 +24,7 @@
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
#include "DisplayEventConnection.h"
@@ -51,6 +51,11 @@
status_t unregisterDisplayEventConnection(
const wp<DisplayEventConnection>& connection);
+ void setVsyncRate(uint32_t count,
+ const wp<DisplayEventConnection>& connection);
+
+ void requestNextVsync(const wp<DisplayEventConnection>& connection);
+
void dump(String8& result, char* buffer, size_t SIZE) const;
private:
@@ -58,7 +63,20 @@
virtual status_t readyToRun();
virtual void onFirstRef();
- status_t removeDisplayEventConnection(
+ struct ConnectionInfo {
+ ConnectionInfo() : count(-1) { }
+
+ // count >= 1 : continuous event. count is the vsync rate
+ // count == 0 : one-shot event that has not fired
+ // count ==-1 : one-shot event that fired this round / disabled
+ // count ==-2 : one-shot event that fired the round before
+ int32_t count;
+ };
+
+ void removeDisplayEventConnection(
+ const wp<DisplayEventConnection>& connection);
+
+ ConnectionInfo* getConnectionInfoLocked(
const wp<DisplayEventConnection>& connection);
// constants
@@ -69,7 +87,9 @@
mutable Condition mCondition;
// protected by mLock
- SortedVector<wp<DisplayEventConnection> > mDisplayEventConnections;
+ KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > mDisplayEventConnections;
+
+ // main thread only
size_t mDeliveredEvents;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 58196d8..014c7e2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -389,16 +389,10 @@
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
- sp<DisplayEventConnection> result(new DisplayEventConnection(this));
- mEventThread->registerDisplayEventConnection(result);
+ sp<DisplayEventConnection> result(new DisplayEventConnection(mEventThread));
return result;
}
-void SurfaceFlinger::cleanupDisplayEventConnection(
- const wp<DisplayEventConnection>& connection) {
- mEventThread->unregisterDisplayEventConnection(connection);
-}
-
// ----------------------------------------------------------------------------
#if 0
#pragma mark -
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e6d2cd9..41caee3 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -335,9 +335,6 @@
status_t electronBeamOffAnimationImplLocked();
status_t electronBeamOnAnimationImplLocked();
- void cleanupDisplayEventConnection(
- const wp<DisplayEventConnection>& connection);
-
void debugFlashRegions();
void debugShowFPS() const;
void drawWormhole() const;
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index f111dd6..07b6183 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -683,6 +683,13 @@
mRilConnectedRegistrants.remove(h);
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setCurrentPreferredNetworkType() {
+ }
+
//***** Protected Methods
/**
* Store new RadioState and send notification based on the changes
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 33ead75..d6e6ae0 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1311,6 +1311,12 @@
void queryAvailableBandMode (Message response);
/**
+ * Set the current preferred network type. This will be the last
+ * networkType that was passed to setPreferredNetworkType.
+ */
+ void setCurrentPreferredNetworkType();
+
+ /**
* Requests to set the preferred network type for searching and registering
* (CS/PS domain, RAT, and operation mode)
* @param networkType one of NT_*_TYPE
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 9f93fb8..f2e7f45 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1823,6 +1823,16 @@
/**
* {@inheritDoc}
*/
+ @Override
+ public void setCurrentPreferredNetworkType() {
+ if (RILJ_LOGD) riljLog("setCurrentPreferredNetworkType: " + mSetPreferredNetworkType);
+ setPreferredNetworkType(mSetPreferredNetworkType, null);
+ }
+ private int mSetPreferredNetworkType;
+
+ /**
+ * {@inheritDoc}
+ */
public void setPreferredNetworkType(int networkType , Message response) {
RILRequest rr = RILRequest.obtain(
RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, response);
@@ -1830,6 +1840,7 @@
rr.mp.writeInt(1);
rr.mp.writeInt(networkType);
+ mSetPreferredNetworkType = networkType;
mPreferredNetworkType = networkType;
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 3d6cd68..d939e98 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -257,6 +257,9 @@
break;
case EVENT_RUIM_READY:
+ // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST.
+ // cm.setCurrentPreferredNetworkType();
+
// The RUIM is now ready i.e if it was locked it has been
// unlocked. At this stage, the radio is already powered on.
isSubscriptionFromRuim = true;
@@ -277,6 +280,9 @@
break;
case EVENT_NV_READY:
+ // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST.
+ // cm.setCurrentPreferredNetworkType();
+
isSubscriptionFromRuim = false;
// For Non-RUIM phones, the subscription information is stored in
// Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 11f1623..963db2c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -914,10 +914,16 @@
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
+ NetworkUtils.trimV4AddrZeros(
+ cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
+ NetworkUtils.trimV4AddrZeros(
+ cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
+ NetworkUtils.trimV4AddrZeros(
+ cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 3799894..16d3129 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -132,7 +132,7 @@
// See TS 22.030 6.5.2 "Structure of the MMI"
static Pattern sPatternSuppService = Pattern.compile(
- "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)");
+ "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)([^#]*)");
/* 1 2 3 4 5 6 7 8 9 10 11 12
1 = Full string up to and including #
@@ -141,7 +141,7 @@
5 = SIA
7 = SIB
9 = SIC
- 10 = dialing number
+ 10 = dialing number which must not include #, e.g. *SCn*SI#DN format
*/
static final int MATCH_GROUP_POUND_STRING = 1;
@@ -1338,4 +1338,20 @@
* SpecialCharSequenceMgr class.
*/
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("GsmMmiCode {");
+
+ sb.append("State=" + getState());
+ if (action != null) sb.append(" action=" + action);
+ if (sc != null) sb.append(" sc=" + sc);
+ if (sia != null) sb.append(" sia=" + sia);
+ if (sib != null) sb.append(" sib=" + sib);
+ if (sic != null) sb.append(" sic=" + sic);
+ if (poundString != null) sb.append(" poundString=" + poundString);
+ if (dialingNumber != null) sb.append(" dialingNumber=" + dialingNumber);
+ if (pwd != null) sb.append(" pwd=" + pwd);
+ sb.append("}");
+ return sb.toString();
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index eea2780..84127cf 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -270,6 +270,9 @@
break;
case EVENT_SIM_READY:
+ // Set the network type, in case the radio does not restore it.
+ cm.setCurrentPreferredNetworkType();
+
// The SIM is now ready i.e if it was locked
// it has been unlocked. At this stage, the radio is already
// powered on.
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
index 8cec409..de2a0a7 100644
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
+++ b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
@@ -48,6 +48,14 @@
static float gLastX;
static float gLastY;
+static float3 toFloat3(float x, float y, float z) {
+ float3 f;
+ f.x = x;
+ f.y = y;
+ f.z = z;
+ return f;
+}
+
void onActionDown(float x, float y) {
gLastX = x;
gLastY = y;
@@ -104,8 +112,8 @@
rsgMeshComputeBoundingBox(info->mMesh,
&minX, &minY, &minZ,
&maxX, &maxY, &maxZ);
- info->bBoxMin = (minX, minY, minZ);
- info->bBoxMax = (maxX, maxY, maxZ);
+ info->bBoxMin = toFloat3(minX, minY, minZ);
+ info->bBoxMax = toFloat3(maxX, maxY, maxZ);
gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
}
gLookAt = gLookAt / (float)size;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
index 06b4af7..ba70c71 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
@@ -62,6 +62,9 @@
mTests[index].testName = Allocation.createFromString(mRS,
mNames[index],
Allocation.USAGE_SCRIPT);
+ mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+ mNames[index],
+ Allocation.USAGE_SCRIPT);
ScriptField_FillTestData_s.Item dataItem = new ScriptField_FillTestData_s.Item();
dataItem.testId = testId;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
index f39e7db..cdb4435 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
@@ -69,6 +69,9 @@
mTests[index].testName = Allocation.createFromString(mRS,
mNames[index],
Allocation.USAGE_SCRIPT);
+ mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+ mNames[index],
+ Allocation.USAGE_SCRIPT);
ScriptField_MeshTestData_s.Item dataItem = new ScriptField_MeshTestData_s.Item();
dataItem.meshNum = meshNum;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
index c51bd82..8c67026 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
@@ -60,7 +60,6 @@
mWidth = width;
mHeight = height;
mMode = 0;
- mMaxModes = 0;
mLoops = loops;
mCurrentLoop = 0;
mBenchmarkDimX = 1280;
@@ -88,11 +87,30 @@
ScriptField_TestScripts_s.Item[] mIndividualTests;
int mMode;
- int mMaxModes;
String[] mTestNames;
float[] mLocalTestResults;
+ static Allocation createZeroTerminatedAlloc(RenderScript rs,
+ String str,
+ int usage) {
+ byte[] allocArray = null;
+ try {
+ allocArray = str.getBytes("UTF-8");
+ byte[] allocArrayZero = new byte[allocArray.length + 1];
+ System.arraycopy(allocArray, 0, allocArrayZero, 0, allocArray.length);
+ allocArrayZero[allocArrayZero.length - 1] = '\0';
+ Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
+ allocArrayZero.length, usage);
+ alloc.copyFrom(allocArrayZero);
+ return alloc;
+ }
+ catch (Exception e) {
+ throw new RSRuntimeException("Could not convert string to utf-8.");
+ }
+
+ }
+
void appendTests(RsBenchBaseTest testSet) {
ScriptField_TestScripts_s.Item[] newTests = testSet.getTests();
if (mIndividualTests != null) {
@@ -119,6 +137,7 @@
void createTestAllocation() {
int numTests = mIndividualTests.length;
+ mLocalTestResults = new float[numTests];
ScriptField_TestScripts_s allTests;
allTests = new ScriptField_TestScripts_s(mRS, numTests);
for (int i = 0; i < numTests; i ++) {
@@ -239,11 +258,6 @@
return count;
}
- private void prepareTestData() {
- mTestNames = new String[mMaxModes];
- mLocalTestResults = new float[mMaxModes];
- }
-
public void setDebugMode(int num) {
mScript.invoke_setDebugMode(num);
}
@@ -261,8 +275,6 @@
mScript.set_gMaxLoops(mLoops);
- prepareTestData();
-
initProgramVertex();
initProgramFragment();
mScript.set_gFontSerif(Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8));
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
index ca9e660..3ca2792 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
@@ -48,6 +48,9 @@
mTests[index].testName = Allocation.createFromString(mRS,
mNames[index],
Allocation.USAGE_SCRIPT);
+ mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+ mNames[index],
+ Allocation.USAGE_SCRIPT);
ScriptField_TextTestData_s.Item dataItem = new ScriptField_TextTestData_s.Item();
dataItem.fillNum = fillNum;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
index d785dc1..5c9ecd5 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
@@ -98,6 +98,9 @@
mTests[index].testName = Allocation.createFromString(mRS,
mNames[index],
Allocation.USAGE_SCRIPT);
+ mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+ mNames[index],
+ Allocation.USAGE_SCRIPT);
ScriptField_TorusTestData_s.Item dataItem = new ScriptField_TorusTestData_s.Item();
dataItem.testId = testId;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
index cca237e..c8b58b2 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
@@ -82,6 +82,9 @@
mTests[index].testName = Allocation.createFromString(mRS,
mNames[index],
Allocation.USAGE_SCRIPT);
+ mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+ mNames[index],
+ Allocation.USAGE_SCRIPT);
ScriptField_UiTestData_s.Item dataItem = new ScriptField_UiTestData_s.Item();
dataItem.testId = testId;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index 2b849a2..cb15449 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -45,6 +45,7 @@
typedef struct TestScripts_s {
rs_allocation testData;
rs_allocation testName;
+ rs_allocation debugName;
rs_script testScript;
} TestScripts;
TestScripts *gTestScripts;
@@ -195,7 +196,8 @@
int64_t end = rsUptimeMillis();
float fps = (float)(frameCount) / ((float)(end - start)*0.001f);
- rsDebug("Finishes test ", fps);
+ const char *testName = rsGetElementAt(gTestScripts[benchMode].debugName, 0);
+ rsDebug(testName, fps);
gResultBuffer[benchMode] = fps;
int bufferW = rsAllocationGetDimX(gRenderBufferColor);
diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
index 53f10f9..ae32e3a 100644
--- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
+++ b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
@@ -57,6 +57,14 @@
static float gLastX;
static float gLastY;
+static float3 toFloat3(float x, float y, float z) {
+ float3 f;
+ f.x = x;
+ f.y = y;
+ f.z = z;
+ return f;
+}
+
void onActionDown(float x, float y) {
gLastX = x;
gLastY = y;
@@ -112,8 +120,8 @@
rsgMeshComputeBoundingBox(info->mMesh,
&minX, &minY, &minZ,
&maxX, &maxY, &maxZ);
- info->bBoxMin = (minX, minY, minZ);
- info->bBoxMax = (maxX, maxY, maxZ);
+ info->bBoxMin = toFloat3(minX, minY, minZ);
+ info->bBoxMax = toFloat3(maxX, maxY, maxZ);
gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
}
gLookAt = gLookAt / (float)size;
diff --git a/tests/StatusBar/res/layout/notification_builder_test.xml b/tests/StatusBar/res/layout/notification_builder_test.xml
index e1199c7..6c384f7 100644
--- a/tests/StatusBar/res/layout/notification_builder_test.xml
+++ b/tests/StatusBar/res/layout/notification_builder_test.xml
@@ -605,6 +605,11 @@
style="@style/FieldContents"
android:text="pineapple2"
/>
+ <RadioButton
+ android:id="@+id/large_icon_small"
+ style="@style/FieldContents"
+ android:text="small"
+ />
</RadioGroup>
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
index 5a2ebac..fefd890 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
@@ -287,6 +287,9 @@
case R.id.large_icon_pineapple2:
b.setLargeIcon(loadBitmap(R.drawable.pineapple2));
break;
+ case R.id.large_icon_small:
+ b.setLargeIcon(loadBitmap(R.drawable.icon2));
+ break;
}
// sound TODO
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 637c27d..d7ac15e 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -625,6 +625,11 @@
bool actImeService = false;
bool actWallpaperService = false;
+ // These two implement the implicit permissions that are granted
+ // to pre-1.6 applications.
+ bool hasWriteExternalStoragePermission = false;
+ bool hasReadPhoneStatePermission = false;
+
// This next group of variables is used to implement a group of
// backward-compatibility heuristics necessitated by the addition of
// some new uses-feature constants in 2.1 and 2.2. In most cases, the
@@ -986,6 +991,10 @@
name == "android.permission.WRITE_APN_SETTINGS" ||
name == "android.permission.WRITE_SMS") {
hasTelephonyPermission = true;
+ } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
+ hasWriteExternalStoragePermission = true;
+ } else if (name == "android.permission.READ_PHONE_STATE") {
+ hasReadPhoneStatePermission = true;
}
printf("uses-permission:'%s'\n", name.string());
} else {
@@ -1144,6 +1153,16 @@
}
}
+ // Pre-1.6 implicitly granted permission compatibility logic
+ if (targetSdk < 4) {
+ if (!hasWriteExternalStoragePermission) {
+ printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n");
+ }
+ if (!hasReadPhoneStatePermission) {
+ printf("uses-permission:'android.permission.READ_PHONE_STATE'\n");
+ }
+ }
+
/* The following blocks handle printing "inferred" uses-features, based
* on whether related features or permissions are used by the app.
* Note that the various spec*Feature variables denote whether the
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 253e0ec..ae8f466 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -306,8 +306,6 @@
static final int CMD_SET_HIGH_PERF_MODE = BASE + 77;
/* Set the country code */
static final int CMD_SET_COUNTRY_CODE = BASE + 80;
- /* Request connectivity manager wake lock before driver stop */
- static final int CMD_REQUEST_CM_WAKELOCK = BASE + 81;
/* Enables RSSI poll */
static final int CMD_ENABLE_RSSI_POLL = BASE + 82;
/* RSSI poll */
@@ -1061,15 +1059,6 @@
return result;
}
- /**
- * Request a wakelock with connectivity service to
- * keep the device awake until we hand-off from wifi
- * to an alternate network
- */
- public void requestCmWakeLock() {
- sendMessage(CMD_REQUEST_CM_WAKELOCK);
- }
-
public void updateBatteryWorkSource(WorkSource newSource) {
synchronized (mRunningWifiUids) {
try {
@@ -1867,7 +1856,6 @@
case CMD_SET_HIGH_PERF_MODE:
case CMD_SET_COUNTRY_CODE:
case CMD_SET_FREQUENCY_BAND:
- case CMD_REQUEST_CM_WAKELOCK:
case CMD_CONNECT_NETWORK:
case CMD_SAVE_NETWORK:
case CMD_FORGET_NETWORK:
@@ -3024,10 +3012,6 @@
WifiNative.disconnectCommand();
transitionTo(mDisconnectingState);
break;
- case CMD_REQUEST_CM_WAKELOCK:
- checkAndSetConnectivityInstance();
- mCm.requestNetworkTransitionWakelock(TAG);
- break;
case CMD_SET_SCAN_MODE:
if (message.arg1 == SCAN_ONLY_MODE) {
sendMessage(CMD_DISCONNECT);
@@ -3100,6 +3084,11 @@
}
@Override
public void exit() {
+
+ /* Request a CS wakelock during transition to mobile */
+ checkAndSetConnectivityInstance();
+ mCm.requestNetworkTransitionWakelock(TAG);
+
/* If a scan result is pending in connected state, the supplicant
* is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
*/
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index f330c32..b27c60f 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -150,6 +150,7 @@
private ConnectedState mConnectedState = new ConnectedState();
private DnsCheckingState mDnsCheckingState = new DnsCheckingState();
private OnlineWatchState mOnlineWatchState = new OnlineWatchState();
+ private OnlineState mOnlineState = new OnlineState();
private DnsCheckFailureState mDnsCheckFailureState = new DnsCheckFailureState();
private DelayWalledGardenState mDelayWalledGardenState = new DelayWalledGardenState();
private WalledGardenState mWalledGardenState = new WalledGardenState();
@@ -163,6 +164,7 @@
private int mMinDnsResponses;
private int mDnsPingTimeoutMs;
private long mBlacklistFollowupIntervalMs;
+ private boolean mPoorNetworkDetectionEnabled;
private boolean mWalledGardenTestEnabled;
private String mWalledGardenUrl;
@@ -226,6 +228,7 @@
addState(mWalledGardenState, mConnectedState);
addState(mBlacklistedApState, mConnectedState);
addState(mOnlineWatchState, mConnectedState);
+ addState(mOnlineState, mConnectedState);
setInitialState(mWatchdogDisabledState);
updateSettings();
@@ -411,6 +414,10 @@
mBlacklistFollowupIntervalMs = Secure.getLong(mContentResolver,
Settings.Secure.WIFI_WATCHDOG_BLACKLIST_FOLLOWUP_INTERVAL_MS,
DEFAULT_BLACKLIST_FOLLOWUP_INTERVAL_MS);
+ //TODO: enable this by default after changing watchdog behavior
+ //Also, update settings description
+ mPoorNetworkDetectionEnabled = getSettingsBoolean(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED, false);
mWalledGardenTestEnabled = getSettingsBoolean(mContentResolver,
Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED, true);
mWalledGardenUrl = getSettingsStr(mContentResolver,
@@ -623,9 +630,13 @@
initConnection(wifiInfo);
mConnectionInfo = wifiInfo;
- updateBssids();
- transitionTo(mDnsCheckingState);
mNetEventCounter++;
+ if (mPoorNetworkDetectionEnabled) {
+ updateBssids();
+ transitionTo(mDnsCheckingState);
+ } else {
+ transitionTo(mDelayWalledGardenState);
+ }
break;
default:
mNetEventCounter++;
@@ -677,12 +688,18 @@
public boolean processMessage(Message msg) {
switch (msg.what) {
case EVENT_SCAN_RESULTS_AVAILABLE:
- updateBssids();
+ if (mPoorNetworkDetectionEnabled) {
+ updateBssids();
+ }
return HANDLED;
case EVENT_WATCHDOG_SETTINGS_CHANGE:
- // Stop current checks, but let state update
- transitionTo(mOnlineWatchState);
- return NOT_HANDLED;
+ updateSettings();
+ if (mPoorNetworkDetectionEnabled) {
+ transitionTo(mOnlineWatchState);
+ } else {
+ transitionTo(mOnlineState);
+ }
+ return HANDLED;
}
return NOT_HANDLED;
}
@@ -829,7 +846,11 @@
transitionTo(mWalledGardenState);
} else {
if (DBG) log("Walled garden test complete - online");
- transitionTo(mOnlineWatchState);
+ if (mPoorNetworkDetectionEnabled) {
+ transitionTo(mOnlineWatchState);
+ } else {
+ transitionTo(mOnlineState);
+ }
}
return HANDLED;
default:
@@ -961,6 +982,13 @@
}
}
+
+ /* Child state of ConnectedState indicating that we are online
+ * and there is nothing to do
+ */
+ class OnlineState extends State {
+ }
+
class DnsCheckFailureState extends State {
@Override
@@ -1037,7 +1065,11 @@
return HANDLED;
}
setWalledGardenNotificationVisible(true);
- transitionTo(mOnlineWatchState);
+ if (mPoorNetworkDetectionEnabled) {
+ transitionTo(mOnlineWatchState);
+ } else {
+ transitionTo(mOnlineState);
+ }
return HANDLED;
}
}